forked from 12to11/12to11
Add support for EGL, for YUV image formats
EGL support is still incomplete; stuff like scaling is missing. * 12to11.c (PickVisual, XLMain): Remove function. Initialize renderers, and rely on that to initialize the visuals. * 12to11.man: Document new environment variables. * Imakefile (SRCS, OBJS): Add picture_renderer.c and renderer.c and their associated objects. (GENHEADERS): New variable for generated headers. (EGL_SRCS, EGL_OBJS): New variables. (LOCAL_LIBRARIES, SRCS, OBJS, DEFINES): [HaveEglSupport]: Add EGL defines, libraries, and objects.:(shaders.h): New rule. (depend, cleandir): Depend on generated headers and SRCs. $($(OBJS)): Depend on $(GENHEADERS). * README: Write how to build with EGL support and update content descriptions. * buffer.c (XLPictureFromBuffer): Delete function. (XLRenderBufferFromBuffer): New function. (XLPixmapFromBuffer): Delete function. * compositor.h (enum _Operation, struct _SharedMemoryAttributes) (struct _DmaBufAttributes, union _RenderTarget) (union _RenderBuffer, struct _RenderFuncs, struct _DrmFormat) (struct _ShmFormat, struct _BufferFuncs, struct _ExtBufferFuncs): New structures. (Fallthrough): New define. Define to __attribute__ ((fallthrough)) wherever supported. Replace uses of Picture with RenderBuffer. * dmabuf.c (struct _DrmFormatInfo): Remove structures. (struct _BufferParams): Remove link. (struct _Buffer): Replace pixmap and picture with render buffer object. (dri3_opcode, all_formats, pending_success, next_roundtrip_id) (round_trip_window): Delete. (ReleaseBufferParams, HandleParamsResourceDestroy, ForceRoundTrip) (DepthForFormat, XLHandleErrorForDmabuf, PictFormatForFormat) (DestroyBacking, GetPictureFunc, GetPixmapFunc, GetBufferFunc) (CreateBufferFor, ModifierHigh, FinishBufferCreation) (XLHandleOneXEventForDmabuf, CreateHeader, Create, CreateImmed) (FindFormatMatching, FindSupportedModifiers, FindSupportedFormats) (SendSupportedFormats, HandleBind, InitDrmDevice, WriteFormatTable) (ReallyInitDmabuf, ReadSupportedFormats, XLInitDmabuf): Remove various functions and reimplement as a wrapper around the renderer abstraction, instead of DRI3. * fns.c (struct _Busfault): New structure. (busfault_tree, bus_handler_installed): New variables. (GetHeight, FixHeights, RotateLeft, RotateRight, RebalanceBusfault) (RecordBusfault, DetectBusfault, DeleteMin, RemoveBusfault) (HandleBusfault, MaybeInstallBusHandler, BlockSigbus) (UnblockSigbus, XLRecordBusfault, XLRemoveBusfaults): New functions to store non-overlapping regions of mapped memory in an AVL tree, and to ignore SIGBUS events that trap within. * icon_surface.c (struct _IconSurface): Replace picture with rendering target. (ReleaseBacking, XLGetIconSurface): Use rendering targets instead of pictures. * libraries.def: Add defines for EGL. * run.c (HandleOneXEvent): Replace old dmabuf code with renderer code. * seat.c (CursorFromRole, PictureForCursor, ApplyCursor) (UpdateCursorFromSubcompositor, Subframe, EndSubframe): Rewrite cursor code to use rendering targets and not pictures. * shm.c (Buffer, DereferencePool): Remove SIGBUS protection. (DereferenceBuffer): Reimplement in terms of renderer functions. (GetPictureFunc): Delete function. (GetBufferFunc): New function. (GetPixmapFunc): Delete function. (PrintBuffer): Remove now-broken implementation. (DepthForFormat, PictFormatForFormat): Delete functions, as they are now part of the rendering backend. (IsFormatSupported): New function. (CreateBuffer): Reimplement in terms of renderer functions. (ResizePool): Change SIGBUS protection for resize. (CreatePool): Protect buffer data from SIGBUS should a client truncate the file. (PostFormats): Reimplement in terms of RenderGetShmFormats. (XLInitShm): Stop initializing MIT-SHM. * subcompositor.c (IsTargetAttached): New flag and associated macros. (struct _View): Remove useless field. (struct _Subcompositor): Change target to RenderTarget. Add fields for prior damage. (MakeSubcompositor): Initialize new fields. (SubcompositorSetTarget): Accept RenderTarget, not picture, and set target attached flag. (ViewGetTransform): Delete function. (ViewApplyTransform): New function. (FillBoxesWithTransparency): Reimplement in terms of renderer functions. (StorePreviousDamage): New function. (SubcompositorUpdate): Reimplement in terms of renderer functions. Also, learn to deal with situations where the buffer reflects the state 1 to 2 swaps ago. (SubcompositorExpose): Reimplement in terms of renderer functions. (SubcompositorFree): Free new fields. (SubcompositorInit): Remove no longer required initialization of identity matrix. * xdata.c (ReceiveBody): Fix coding style. * xdg_surface.c (struct _XdgRole, ReleaseBacking, XLGetXdgSurface): Switch from pictures to RenderTargets. * xerror.c (ErrorHandler): Handle errors for picture renderer instead of dmabuf.c.
This commit is contained in:
parent
970b60268f
commit
b4ee06589e
17 changed files with 1606 additions and 1181 deletions
40
12to11.c
40
12to11.c
|
@ -28,35 +28,6 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
/* Globals. */
|
/* Globals. */
|
||||||
Compositor compositor;
|
Compositor compositor;
|
||||||
|
|
||||||
static Visual *
|
|
||||||
PickVisual (int *depth)
|
|
||||||
{
|
|
||||||
int n_visuals;
|
|
||||||
XVisualInfo vinfo, *visuals;
|
|
||||||
Visual *selection;
|
|
||||||
|
|
||||||
vinfo.screen = DefaultScreen (compositor.display);
|
|
||||||
vinfo.class = TrueColor;
|
|
||||||
vinfo.depth = 32;
|
|
||||||
|
|
||||||
visuals = XGetVisualInfo (compositor.display, (VisualScreenMask
|
|
||||||
| VisualClassMask
|
|
||||||
| VisualDepthMask),
|
|
||||||
&vinfo, &n_visuals);
|
|
||||||
|
|
||||||
if (n_visuals)
|
|
||||||
{
|
|
||||||
selection = visuals[0].visual;
|
|
||||||
*depth = visuals[0].depth;
|
|
||||||
XFree (visuals);
|
|
||||||
|
|
||||||
return selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "A 32-bit TrueColor visual was not found\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Colormap
|
static Colormap
|
||||||
MakeColormap (void)
|
MakeColormap (void)
|
||||||
{
|
{
|
||||||
|
@ -129,8 +100,6 @@ XLMain (int argc, char **argv)
|
||||||
compositor.wl_socket = socket;
|
compositor.wl_socket = socket;
|
||||||
compositor.wl_event_loop
|
compositor.wl_event_loop
|
||||||
= wl_display_get_event_loop (wl_display);
|
= wl_display_get_event_loop (wl_display);
|
||||||
compositor.visual = PickVisual (&compositor.n_planes);
|
|
||||||
compositor.colormap = MakeColormap ();
|
|
||||||
|
|
||||||
InitXErrors ();
|
InitXErrors ();
|
||||||
SubcompositorInit ();
|
SubcompositorInit ();
|
||||||
|
@ -138,6 +107,15 @@ XLMain (int argc, char **argv)
|
||||||
|
|
||||||
XLInitTimers ();
|
XLInitTimers ();
|
||||||
XLInitAtoms ();
|
XLInitAtoms ();
|
||||||
|
|
||||||
|
/* Initialize renderers immediately after timers and atoms are set
|
||||||
|
up. */
|
||||||
|
InitRenderers ();
|
||||||
|
|
||||||
|
/* Set up the colormap. Initializing renderers should also cause
|
||||||
|
the visual to be set. */
|
||||||
|
compositor.colormap = MakeColormap ();
|
||||||
|
|
||||||
XLInitRROutputs ();
|
XLInitRROutputs ();
|
||||||
XLInitCompositor ();
|
XLInitCompositor ();
|
||||||
XLInitSurfaces ();
|
XLInitSurfaces ();
|
||||||
|
|
12
12to11.man
12
12to11.man
|
@ -67,6 +67,18 @@ variable, if set, forces ConfigureNotify events from the window
|
||||||
manager to be handled directly, without waiting some time for a
|
manager to be handled directly, without waiting some time for a
|
||||||
corresponding _NET_WM_STATE event to arrive. This is only
|
corresponding _NET_WM_STATE event to arrive. This is only
|
||||||
useful for debugging the window resizing logic.
|
useful for debugging the window resizing logic.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B RENDERER
|
||||||
|
variable, if set, controls the rendering backend used by the
|
||||||
|
protocol translator. When set to
|
||||||
|
.I help
|
||||||
|
it prints a list of available rendering backends instead.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B RENDER_VISUAL
|
||||||
|
variable, if set to a number, contains the ID of the visual used
|
||||||
|
when the EGL rendering backend is in use.
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
There is a hard to catch bug where Wayland programs leaving the
|
There is a hard to catch bug where Wayland programs leaving the
|
||||||
fullscreen or maximized state may abruptly return to their maximized
|
fullscreen or maximized state may abruptly return to their maximized
|
||||||
|
|
37
Imakefile
37
Imakefile
|
@ -22,7 +22,8 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
|
||||||
frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c \
|
frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c \
|
||||||
data_device.c xdg_popup.c linux-dmabuf-unstable-v1.c dmabuf.c \
|
data_device.c xdg_popup.c linux-dmabuf-unstable-v1.c dmabuf.c \
|
||||||
buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c \
|
buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c \
|
||||||
primary-selection-unstable-v1.c primary_selection.c
|
primary-selection-unstable-v1.c primary_selection.c \
|
||||||
|
renderer.c picture_renderer.c
|
||||||
|
|
||||||
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
||||||
xdg-shell.o surface.o region.o shm.o atoms.o subcompositor.o \
|
xdg-shell.o surface.o region.o shm.o atoms.o subcompositor.o \
|
||||||
|
@ -30,7 +31,32 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
||||||
frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o \
|
frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o \
|
||||||
data_device.o xdg_popup.o linux-dmabuf-unstable-v1.o dmabuf.o \
|
data_device.o xdg_popup.o linux-dmabuf-unstable-v1.o dmabuf.o \
|
||||||
buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o \
|
buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o \
|
||||||
primary-selection-unstable-v1.o primary_selection.o
|
primary-selection-unstable-v1.o primary_selection.o \
|
||||||
|
renderer.o picture_renderer.o
|
||||||
|
|
||||||
|
GENHEADERS = transfer_atoms.h primary-selection-unstable-v1.h \
|
||||||
|
linux-dmabuf-unstable-v1.h xdg-shell.h
|
||||||
|
|
||||||
|
#ifdef HaveEglSupport
|
||||||
|
|
||||||
|
EGL_SRCS = egl.c
|
||||||
|
EGL_OBJS = egl.o
|
||||||
|
LOCAL_LIBRARIES ::= $(LOCAL_LIBRARIES) $(EGL) $(GLES)
|
||||||
|
SRCS ::= $(SRCS) $(EGL_SRCS)
|
||||||
|
OBJS ::= $(OBJS) $(EGL_OBJS)
|
||||||
|
DEFINES ::= $(DEFINES) -DHaveEglSupport
|
||||||
|
|
||||||
|
shaders.h: shaders.txt shaders.awk
|
||||||
|
awk -f shaders.awk shaders.txt > $@
|
||||||
|
|
||||||
|
depend:: shaders.h
|
||||||
|
|
||||||
|
$(EGL_OBJS): shaders.h
|
||||||
|
|
||||||
|
cleandir::
|
||||||
|
$(RM) shaders.h
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
OPTIMIZE = -O0
|
OPTIMIZE = -O0
|
||||||
ANALYZE = -fanalyzer
|
ANALYZE = -fanalyzer
|
||||||
|
@ -68,8 +94,11 @@ transfer_atoms.h: short_types.txt mime0.awk mime1.awk mime2.awk mime3.awk \
|
||||||
awk -f mime3.awk short_types.txt >> $@
|
awk -f mime3.awk short_types.txt >> $@
|
||||||
awk -f mime4.awk short_types.txt >> $@
|
awk -f mime4.awk short_types.txt >> $@
|
||||||
|
|
||||||
$(OBJS): transfer_atoms.h primary-selection-unstable-v1.h \
|
$(OBJS): $(GENHEADERS)
|
||||||
linux-dmabuf-unstable-v1.h xdg-shell.h
|
|
||||||
|
/* depend somehow does not depend on SRCS, even though some of OBJS
|
||||||
|
are generated. */
|
||||||
|
depend:: $(GENHEADERS) $(SRCS)
|
||||||
|
|
||||||
linux-dmabuf-unstable-v1.h: linux-dmabuf-unstable-v1.xml
|
linux-dmabuf-unstable-v1.h: linux-dmabuf-unstable-v1.xml
|
||||||
$(WAYLAND_SCANNER) server-header $< $@
|
$(WAYLAND_SCANNER) server-header $< $@
|
||||||
|
|
24
README
24
README
|
@ -31,6 +31,27 @@ extensions:
|
||||||
In addition, it requires Xlib to be built with the XCB transport, and
|
In addition, it requires Xlib to be built with the XCB transport, and
|
||||||
the XCB bindings for MIT-SHM and DRI3 to be available.
|
the XCB bindings for MIT-SHM and DRI3 to be available.
|
||||||
|
|
||||||
|
Sometimes, it might be desirable to build with EGL, and use OpenGL ES
|
||||||
|
2.0 for i.e. YUV video format support. To do so, uncomment the block
|
||||||
|
of code for EGL support in libraries.def before running `xmkmf'. This
|
||||||
|
will additionally require the EGL and GLESv2 development files, and
|
||||||
|
for the following EGL and GLES extensions to be present at runtime:
|
||||||
|
|
||||||
|
EGL_EXT_platform_base
|
||||||
|
EGL_EXT_device_query
|
||||||
|
EGL_KHR_image_base
|
||||||
|
EGL_EXT_image_dma_buf_import_modifiers
|
||||||
|
EGL_EXT_image_dma_buf_import
|
||||||
|
EGL_EXT_buffer_age
|
||||||
|
|
||||||
|
GL_OES_EGL_image
|
||||||
|
GL_OES_EGL_image_external
|
||||||
|
GL_EXT_read_format_bgra
|
||||||
|
GL_EXT_unpack_subimage
|
||||||
|
|
||||||
|
After building with EGL support, the renderer must be enabled by
|
||||||
|
setting the environment variable "RENDERER" to "egl".
|
||||||
|
|
||||||
The following Wayland protocols are implemented to a more-or-less
|
The following Wayland protocols are implemented to a more-or-less
|
||||||
complete degree:
|
complete degree:
|
||||||
|
|
||||||
|
@ -58,6 +79,9 @@ This directory is organized as follows:
|
||||||
libraries.def - files for libraries that don't provide Imakefiles
|
libraries.def - files for libraries that don't provide Imakefiles
|
||||||
*.xml - Wayland protocol definition source
|
*.xml - Wayland protocol definition source
|
||||||
*.c, *.h - C source code
|
*.c, *.h - C source code
|
||||||
|
*.awk - scripts used to generate headers
|
||||||
|
*.txt - text data used to generate some headers, i.e.
|
||||||
|
those containing MIME types or shaders
|
||||||
|
|
||||||
Building the source code is simple, provided that you have the
|
Building the source code is simple, provided that you have the
|
||||||
necessary libwayland-server library, wayland-scanner, pixman, XCB, and
|
necessary libwayland-server library, wayland-scanner, pixman, XCB, and
|
||||||
|
|
13
buffer.c
13
buffer.c
|
@ -30,7 +30,6 @@ struct _DestroyListener
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
XLRetainBuffer (ExtBuffer *buffer)
|
XLRetainBuffer (ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
@ -43,16 +42,10 @@ XLDereferenceBuffer (ExtBuffer *buffer)
|
||||||
buffer->funcs.dereference (buffer);
|
buffer->funcs.dereference (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Picture
|
RenderBuffer
|
||||||
XLPictureFromBuffer (ExtBuffer *buffer)
|
XLRenderBufferFromBuffer (ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
return buffer->funcs.get_picture (buffer);
|
return buffer->funcs.get_buffer (buffer);
|
||||||
}
|
|
||||||
|
|
||||||
Pixmap
|
|
||||||
XLPixmapFromBuffer (ExtBuffer *buffer)
|
|
||||||
{
|
|
||||||
return buffer->funcs.get_pixmap (buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
|
|
298
compositor.h
298
compositor.h
|
@ -94,6 +94,271 @@ typedef struct _PDataSource PDataSource;
|
||||||
|
|
||||||
extern Compositor compositor;
|
extern Compositor compositor;
|
||||||
|
|
||||||
|
/* Defined in renderer.c. */
|
||||||
|
|
||||||
|
typedef struct _RenderFuncs RenderFuncs;
|
||||||
|
typedef struct _BufferFuncs BufferFuncs;
|
||||||
|
|
||||||
|
typedef union _RenderTarget RenderTarget;
|
||||||
|
typedef union _RenderBuffer RenderBuffer;
|
||||||
|
|
||||||
|
typedef struct _DmaBufAttributes DmaBufAttributes;
|
||||||
|
typedef struct _SharedMemoryAttributes SharedMemoryAttributes;
|
||||||
|
|
||||||
|
typedef struct _DrmFormat DrmFormat;
|
||||||
|
typedef struct _ShmFormat ShmFormat;
|
||||||
|
|
||||||
|
typedef enum _Operation Operation;
|
||||||
|
|
||||||
|
typedef void (*DmaBufSuccessFunc) (RenderBuffer, void *);
|
||||||
|
typedef void (*DmaBufFailureFunc) (void *);
|
||||||
|
|
||||||
|
enum _Operation
|
||||||
|
{
|
||||||
|
OperationOver,
|
||||||
|
OperationSource,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _SharedMemoryAttributes
|
||||||
|
{
|
||||||
|
/* The format of the buffer. */
|
||||||
|
uint32_t format;
|
||||||
|
|
||||||
|
/* The offset, width, height, and stride of the buffer. */
|
||||||
|
int32_t offset, width, height, stride;
|
||||||
|
|
||||||
|
/* The pool file descriptor. */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Pointer to a pointer to the pool data. */
|
||||||
|
void **data;
|
||||||
|
|
||||||
|
/* Size of the pool. */
|
||||||
|
size_t pool_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _DmaBufAttributes
|
||||||
|
{
|
||||||
|
/* The file descriptors. They should be closed by the time the
|
||||||
|
callback returns. */
|
||||||
|
int fds[4];
|
||||||
|
|
||||||
|
/* The modifier. */
|
||||||
|
uint64_t modifier;
|
||||||
|
|
||||||
|
/* Strides. */
|
||||||
|
unsigned int strides[4];
|
||||||
|
|
||||||
|
/* Offsets. */
|
||||||
|
unsigned int offsets[4];
|
||||||
|
|
||||||
|
/* The number of planes set. */
|
||||||
|
int n_planes;
|
||||||
|
|
||||||
|
/* The width and height of the buffer. */
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
/* Flags. */
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
/* The DRM format of the buffer. */
|
||||||
|
uint32_t drm_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
union _RenderTarget
|
||||||
|
{
|
||||||
|
/* The XID of the target resource, if that is what it is. */
|
||||||
|
XID xid;
|
||||||
|
|
||||||
|
/* The pointer to the target, if that is what it is. */
|
||||||
|
void *pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
union _RenderBuffer
|
||||||
|
{
|
||||||
|
/* The XID of the buffer resource, if that is what it is. */
|
||||||
|
XID xid;
|
||||||
|
|
||||||
|
/* The pointer to the buffer, if that is what it is. */
|
||||||
|
void *pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* The render target always preserves previously drawn contents;
|
||||||
|
IOW, target_age always returns 0. */
|
||||||
|
NeverAges = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _RenderFuncs
|
||||||
|
{
|
||||||
|
/* Initialize the visual and depth. */
|
||||||
|
Bool (*init_render_funcs) (void);
|
||||||
|
|
||||||
|
/* Create a rendering target for the given window. */
|
||||||
|
RenderTarget (*target_from_window) (Window);
|
||||||
|
|
||||||
|
/* Create a rendering target for the given pixmap. */
|
||||||
|
RenderTarget (*target_from_pixmap) (Pixmap);
|
||||||
|
|
||||||
|
/* Set the target width and height. This can be NULL. */
|
||||||
|
void (*note_target_size) (RenderTarget, int, int);
|
||||||
|
|
||||||
|
/* Get an XRender Picture from the given rendering target. The
|
||||||
|
picture should only be used to create a cursor, and must be
|
||||||
|
destroyed by calling FreePictureFromTarget immediately
|
||||||
|
afterwards. */
|
||||||
|
Picture (*picture_from_target) (RenderTarget);
|
||||||
|
|
||||||
|
/* Free a picture created that way. */
|
||||||
|
void (*free_picture_from_target) (Picture);
|
||||||
|
|
||||||
|
/* Destroy the given rendering target. */
|
||||||
|
void (*destroy_render_target) (RenderTarget);
|
||||||
|
|
||||||
|
/* Begin rendering. This can be NULL, but if not, must be called
|
||||||
|
before any drawing operations. */
|
||||||
|
void (*start_render) (RenderTarget);
|
||||||
|
|
||||||
|
/* Fill the target with transparency in the given rectangles. */
|
||||||
|
void (*fill_boxes_with_transparency) (RenderTarget, pixman_box32_t *, int,
|
||||||
|
int, int);
|
||||||
|
|
||||||
|
/* Clear the given rectangle. */
|
||||||
|
void (*clear_rectangle) (RenderTarget, int, int, int, int);
|
||||||
|
|
||||||
|
/* Apply a projective transform to the given buffer. The first
|
||||||
|
argument is a scale factor. */
|
||||||
|
void (*apply_transform) (RenderBuffer, double);
|
||||||
|
|
||||||
|
/* Composite width, height, from the given buffer onto the given
|
||||||
|
target, at x, y. The arguments are: buffer, target, operation,
|
||||||
|
source_x, source_y, x, y, width, height. */
|
||||||
|
void (*composite) (RenderBuffer, RenderTarget, Operation, int, int,
|
||||||
|
int, int, int, int);
|
||||||
|
|
||||||
|
/* Reset the transform for the given buffer. */
|
||||||
|
void (*reset_transform) (RenderBuffer);
|
||||||
|
|
||||||
|
/* Finish rendering, and swap changes to display. May be NULL. */
|
||||||
|
void (*finish_render) (RenderTarget);
|
||||||
|
|
||||||
|
/* Return the age of the target. Value is a number not less than
|
||||||
|
-1, describing the "age" of the contents of the target.
|
||||||
|
|
||||||
|
-1 means the buffer contains no valid contents, and must be
|
||||||
|
redrawn from scratch. 0 means the buffer contains the contents
|
||||||
|
at the time of the last call to `finish_render', 1 means the
|
||||||
|
buffer contains the contents at the time of the second last
|
||||||
|
call to `finish_render', and so on.
|
||||||
|
|
||||||
|
Note that when a render target is first created, the renderer
|
||||||
|
may chose to return 0 instead of 1. */
|
||||||
|
int (*target_age) (RenderTarget);
|
||||||
|
|
||||||
|
/* Some flags. NeverAges means targets always preserve contents
|
||||||
|
that were previously drawn. */
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _DrmFormat
|
||||||
|
{
|
||||||
|
/* The supported DRM format. */
|
||||||
|
uint32_t drm_format;
|
||||||
|
|
||||||
|
/* The supported modifier. */
|
||||||
|
uint64_t drm_modifier;
|
||||||
|
|
||||||
|
/* Backend specific flags associated with this DRM format. */
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _ShmFormat
|
||||||
|
{
|
||||||
|
/* The Wayland type code of the format. */
|
||||||
|
uint32_t format;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _BufferFuncs
|
||||||
|
{
|
||||||
|
/* Get DRM formats and modifiers supported by this renderer. Return
|
||||||
|
0 formats if nothing is supported. */
|
||||||
|
DrmFormat *(*get_drm_formats) (int *);
|
||||||
|
|
||||||
|
/* Get the DRM device node. */
|
||||||
|
dev_t (*get_render_device) (Bool *);
|
||||||
|
|
||||||
|
/* Get SHM formats supported by this renderer. */
|
||||||
|
ShmFormat *(*get_shm_formats) (int *);
|
||||||
|
|
||||||
|
/* Create a buffer from the given dma-buf attributes. */
|
||||||
|
RenderBuffer (*buffer_from_dma_buf) (DmaBufAttributes *, Bool *);
|
||||||
|
|
||||||
|
/* Create a buffer from the given dma-buf attributes
|
||||||
|
asynchronously. */
|
||||||
|
void (*buffer_from_dma_buf_async) (DmaBufAttributes *, DmaBufSuccessFunc,
|
||||||
|
DmaBufFailureFunc, void *);
|
||||||
|
|
||||||
|
/* Create a buffer from the given shared memory attributes. */
|
||||||
|
RenderBuffer (*buffer_from_shm) (SharedMemoryAttributes *, Bool *);
|
||||||
|
|
||||||
|
/* Validate the shared memory attributes passed as args. Return
|
||||||
|
false if they are not valid. */
|
||||||
|
Bool (*validate_shm_params) (uint32_t, uint32_t, uint32_t, int32_t,
|
||||||
|
int32_t, size_t);
|
||||||
|
|
||||||
|
/* Free a buffer created from shared memory. */
|
||||||
|
void (*free_shm_buffer) (RenderBuffer);
|
||||||
|
|
||||||
|
/* Free a dma-buf buffer. */
|
||||||
|
void (*free_dmabuf_buffer) (RenderBuffer);
|
||||||
|
|
||||||
|
/* Notice that the given buffer has been damaged. May be NULL. If
|
||||||
|
the given NULL damage, assume that the entire buffer has been
|
||||||
|
damaged. Must be called at least once before any rendering can
|
||||||
|
be performed on the buffer. */
|
||||||
|
void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *);
|
||||||
|
|
||||||
|
/* Called during renderer initialization. */
|
||||||
|
void (*init_buffer_funcs) (void);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int renderer_flags;
|
||||||
|
|
||||||
|
extern void RegisterStaticRenderer (const char *, RenderFuncs *,
|
||||||
|
BufferFuncs *);
|
||||||
|
extern void InitRenderers (void);
|
||||||
|
|
||||||
|
extern RenderTarget RenderTargetFromWindow (Window);
|
||||||
|
extern RenderTarget RenderTargetFromPixmap (Pixmap);
|
||||||
|
extern void RenderNoteTargetSize (RenderTarget, int, int);
|
||||||
|
extern Picture RenderPictureFromTarget (RenderTarget);
|
||||||
|
extern void RenderFreePictureFromTarget (Picture);
|
||||||
|
extern void RenderDestroyRenderTarget (RenderTarget);
|
||||||
|
extern void RenderStartRender (RenderTarget);
|
||||||
|
extern void RenderFillBoxesWithTransparency (RenderTarget, pixman_box32_t *,
|
||||||
|
int, int, int);
|
||||||
|
extern void RenderClearRectangle (RenderTarget, int, int, int, int);
|
||||||
|
extern void RenderApplyTransform (RenderBuffer, double);
|
||||||
|
extern void RenderComposite (RenderBuffer, RenderTarget, Operation, int,
|
||||||
|
int, int, int, int, int);
|
||||||
|
extern void RenderResetTransform (RenderBuffer);
|
||||||
|
extern void RenderFinishRender (RenderTarget);
|
||||||
|
extern int RenderTargetAge (RenderTarget);
|
||||||
|
|
||||||
|
extern DrmFormat *RenderGetDrmFormats (int *);
|
||||||
|
extern dev_t RenderGetRenderDevice (Bool *);
|
||||||
|
extern ShmFormat *RenderGetShmFormats (int *);
|
||||||
|
extern RenderBuffer RenderBufferFromDmaBuf (DmaBufAttributes *, Bool *);
|
||||||
|
extern void RenderBufferFromDmaBufAsync (DmaBufAttributes *, DmaBufSuccessFunc,
|
||||||
|
DmaBufFailureFunc, void *);
|
||||||
|
extern RenderBuffer RenderBufferFromShm (SharedMemoryAttributes *, Bool *);
|
||||||
|
extern Bool RenderValidateShmParams (uint32_t, uint32_t, uint32_t, int32_t,
|
||||||
|
int32_t, size_t);
|
||||||
|
extern void RenderFreeShmBuffer (RenderBuffer);
|
||||||
|
extern void RenderFreeDmabufBuffer (RenderBuffer);
|
||||||
|
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *);
|
||||||
|
|
||||||
/* Defined in run.c. */
|
/* Defined in run.c. */
|
||||||
|
|
||||||
typedef struct _PollFd WriteFd;
|
typedef struct _PollFd WriteFd;
|
||||||
|
@ -189,6 +454,9 @@ extern Time XLGetServerTimeRoundtrip (void);
|
||||||
extern RootWindowSelection *XLSelectInputFromRootWindow (unsigned long);
|
extern RootWindowSelection *XLSelectInputFromRootWindow (unsigned long);
|
||||||
extern void XLDeselectInputFromRootWindow (RootWindowSelection *);
|
extern void XLDeselectInputFromRootWindow (RootWindowSelection *);
|
||||||
|
|
||||||
|
extern void XLRecordBusfault (void *, size_t);
|
||||||
|
extern void XLRemoveBusfault (void *);
|
||||||
|
|
||||||
/* Defined in compositor.c. */
|
/* Defined in compositor.c. */
|
||||||
|
|
||||||
extern void XLInitCompositor (void);
|
extern void XLInitCompositor (void);
|
||||||
|
@ -209,8 +477,7 @@ struct _ExtBufferFuncs
|
||||||
{
|
{
|
||||||
void (*retain) (ExtBuffer *);
|
void (*retain) (ExtBuffer *);
|
||||||
void (*dereference) (ExtBuffer *);
|
void (*dereference) (ExtBuffer *);
|
||||||
Picture (*get_picture) (ExtBuffer *);
|
RenderBuffer (*get_buffer) (ExtBuffer *);
|
||||||
Pixmap (*get_pixmap) (ExtBuffer *);
|
|
||||||
unsigned int (*width) (ExtBuffer *);
|
unsigned int (*width) (ExtBuffer *);
|
||||||
unsigned int (*height) (ExtBuffer *);
|
unsigned int (*height) (ExtBuffer *);
|
||||||
void (*release) (ExtBuffer *);
|
void (*release) (ExtBuffer *);
|
||||||
|
@ -228,8 +495,7 @@ struct _ExtBuffer
|
||||||
|
|
||||||
extern void XLRetainBuffer (ExtBuffer *);
|
extern void XLRetainBuffer (ExtBuffer *);
|
||||||
extern void XLDereferenceBuffer (ExtBuffer *);
|
extern void XLDereferenceBuffer (ExtBuffer *);
|
||||||
extern Picture XLPictureFromBuffer (ExtBuffer *);
|
extern RenderBuffer XLRenderBufferFromBuffer (ExtBuffer *);
|
||||||
extern Pixmap XLPixmapFromBuffer (ExtBuffer *);
|
|
||||||
extern unsigned int XLBufferWidth (ExtBuffer *);
|
extern unsigned int XLBufferWidth (ExtBuffer *);
|
||||||
extern unsigned int XLBufferHeight (ExtBuffer *);
|
extern unsigned int XLBufferHeight (ExtBuffer *);
|
||||||
extern void XLReleaseBuffer (ExtBuffer *);
|
extern void XLReleaseBuffer (ExtBuffer *);
|
||||||
|
@ -255,7 +521,7 @@ extern void SubcompositorInit (void);
|
||||||
extern Subcompositor *MakeSubcompositor (void);
|
extern Subcompositor *MakeSubcompositor (void);
|
||||||
extern View *MakeView (void);
|
extern View *MakeView (void);
|
||||||
|
|
||||||
extern void SubcompositorSetTarget (Subcompositor *, Picture);
|
extern void SubcompositorSetTarget (Subcompositor *, RenderTarget *);
|
||||||
extern void SubcompositorInsert (Subcompositor *, View *);
|
extern void SubcompositorInsert (Subcompositor *, View *);
|
||||||
extern void SubcompositorInsertBefore (Subcompositor *, View *, View *);
|
extern void SubcompositorInsertBefore (Subcompositor *, View *, View *);
|
||||||
extern void SubcompositorInsertAfter (Subcompositor *, View *, View *);
|
extern void SubcompositorInsertAfter (Subcompositor *, View *, View *);
|
||||||
|
@ -883,8 +1149,6 @@ extern Cursor InitDefaultCursor (void);
|
||||||
/* Defined in dmabuf.c. */
|
/* Defined in dmabuf.c. */
|
||||||
|
|
||||||
extern void XLInitDmabuf (void);
|
extern void XLInitDmabuf (void);
|
||||||
extern Bool XLHandleErrorForDmabuf (XErrorEvent *);
|
|
||||||
extern Bool XLHandleOneXEventForDmabuf (XEvent *);
|
|
||||||
|
|
||||||
/* Defined in select.c. */
|
/* Defined in select.c. */
|
||||||
|
|
||||||
|
@ -985,6 +1249,20 @@ extern Bool XLPDataSourceHasTarget (PDataSource *, const char *);
|
||||||
extern int XLPDataSourceTargetCount (PDataSource *);
|
extern int XLPDataSourceTargetCount (PDataSource *);
|
||||||
extern void XLPDataSourceGetTargets (PDataSource *, Atom *);
|
extern void XLPDataSourceGetTargets (PDataSource *, Atom *);
|
||||||
|
|
||||||
|
/* Defined in picture_renderer.c. */
|
||||||
|
|
||||||
|
extern Bool HandleErrorForPictureRenderer (XErrorEvent *);
|
||||||
|
extern Bool HandleOneXEventForPictureRenderer (XEvent *);
|
||||||
|
extern void InitPictureRenderer (void);
|
||||||
|
|
||||||
|
#ifdef HaveEglSupport
|
||||||
|
|
||||||
|
/* Defined in egl.c. */
|
||||||
|
|
||||||
|
extern void InitEgl (void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Utility functions that don't belong in a specific file. */
|
/* Utility functions that don't belong in a specific file. */
|
||||||
|
|
||||||
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
||||||
|
@ -999,6 +1277,12 @@ extern void XLPDataSourceGetTargets (PDataSource *, Atom *);
|
||||||
|
|
||||||
#define SafeCmp(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))
|
#define SafeCmp(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))
|
||||||
|
|
||||||
|
#if __GNUC__ >= 7
|
||||||
|
#define Fallthrough __attribute__ ((fallthrough))
|
||||||
|
#else
|
||||||
|
#define Fallthrough ((void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Taken from intprops.h in gnulib. */
|
/* Taken from intprops.h in gnulib. */
|
||||||
|
|
||||||
/* True if the real type T is signed. */
|
/* True if the real type T is signed. */
|
||||||
|
|
326
fns.c
326
fns.c
|
@ -22,13 +22,17 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "compositor.h"
|
#include "compositor.h"
|
||||||
|
|
||||||
|
typedef struct _Busfault Busfault;
|
||||||
|
|
||||||
struct _RootWindowSelection
|
struct _RootWindowSelection
|
||||||
{
|
{
|
||||||
/* The next and last event selection records in this chain. */
|
/* The next and last event selection records in this chain. */
|
||||||
|
@ -38,9 +42,30 @@ struct _RootWindowSelection
|
||||||
unsigned long event_mask;
|
unsigned long event_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _Busfault
|
||||||
|
{
|
||||||
|
/* Nodes to the left and right. */
|
||||||
|
Busfault *left, *right;
|
||||||
|
|
||||||
|
/* Start of the ignored area. */
|
||||||
|
char *data;
|
||||||
|
|
||||||
|
/* Size of the ignored area. */
|
||||||
|
size_t ignored_area;
|
||||||
|
|
||||||
|
/* Height of this node. */
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
/* Events that are being selected for on the root window. */
|
/* Events that are being selected for on the root window. */
|
||||||
static RootWindowSelection root_window_events;
|
static RootWindowSelection root_window_events;
|
||||||
|
|
||||||
|
/* All busfaults. */
|
||||||
|
static Busfault *busfault_tree;
|
||||||
|
|
||||||
|
/* Whether or not the SIGBUS handler has been installed. */
|
||||||
|
static Bool bus_handler_installed;
|
||||||
|
|
||||||
void
|
void
|
||||||
XLListFree (XLList *list, void (*item_func) (void *))
|
XLListFree (XLList *list, void (*item_func) (void *))
|
||||||
{
|
{
|
||||||
|
@ -473,3 +498,304 @@ XLDeselectInputFromRootWindow (RootWindowSelection *key)
|
||||||
XLFree (key);
|
XLFree (key);
|
||||||
ReselectRootWindowInput ();
|
ReselectRootWindowInput ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
GetHeight (Busfault *busfault)
|
||||||
|
{
|
||||||
|
if (!busfault)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return busfault->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FixHeights (Busfault *busfault)
|
||||||
|
{
|
||||||
|
XLAssert (busfault != NULL);
|
||||||
|
|
||||||
|
busfault->height = 1 + MAX (GetHeight (busfault->left),
|
||||||
|
GetHeight (busfault->right));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RotateLeft (Busfault **root)
|
||||||
|
{
|
||||||
|
Busfault *old_root, *new_root, *old_middle;
|
||||||
|
|
||||||
|
/* Rotate *root->left to *root. */
|
||||||
|
old_root = *root;
|
||||||
|
new_root = old_root->left;
|
||||||
|
old_middle = new_root->right;
|
||||||
|
old_root->left = old_middle;
|
||||||
|
new_root->right = old_root;
|
||||||
|
*root = new_root;
|
||||||
|
|
||||||
|
/* Update heights. */
|
||||||
|
FixHeights ((*root)->right);
|
||||||
|
FixHeights (*root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RotateRight (Busfault **root)
|
||||||
|
{
|
||||||
|
Busfault *old_root, *new_root, *old_middle;
|
||||||
|
|
||||||
|
/* Rotate *root->right to *root. */
|
||||||
|
old_root = *root;
|
||||||
|
new_root = old_root->right;
|
||||||
|
old_middle = new_root->left;
|
||||||
|
old_root->right = old_middle;
|
||||||
|
new_root->left = old_root;
|
||||||
|
*root = new_root;
|
||||||
|
|
||||||
|
/* Update heights. */
|
||||||
|
FixHeights ((*root)->left);
|
||||||
|
FixHeights (*root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RebalanceBusfault (Busfault **tree)
|
||||||
|
{
|
||||||
|
if (*tree)
|
||||||
|
{
|
||||||
|
/* Check the left. It could be too tall. */
|
||||||
|
if (GetHeight ((*tree)->left)
|
||||||
|
> GetHeight ((*tree)->right) + 1)
|
||||||
|
{
|
||||||
|
/* The left side is unbalanced. Look for a taller
|
||||||
|
grandchild of tree->left. */
|
||||||
|
|
||||||
|
if (GetHeight ((*tree)->left->left)
|
||||||
|
> GetHeight ((*tree)->left->right))
|
||||||
|
RotateLeft (tree);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RotateRight (&(*tree)->left);
|
||||||
|
RotateLeft (tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Then, check the right. */
|
||||||
|
else if (GetHeight ((*tree)->right)
|
||||||
|
> GetHeight ((*tree)->left) + 1)
|
||||||
|
{
|
||||||
|
/* The right side is unbalanced. Look for a taller
|
||||||
|
grandchild of tree->right. */
|
||||||
|
|
||||||
|
if (GetHeight ((*tree)->right->right)
|
||||||
|
> GetHeight ((*tree)->right->left))
|
||||||
|
RotateRight (tree);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RotateLeft (&(*tree)->right);
|
||||||
|
RotateRight (tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing was called, so fix heights. */
|
||||||
|
FixHeights (*tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RecordBusfault (Busfault **tree, Busfault *node)
|
||||||
|
{
|
||||||
|
if (!*tree)
|
||||||
|
{
|
||||||
|
/* Tree is empty. Replace it with node. */
|
||||||
|
*tree = node;
|
||||||
|
node->left = NULL;
|
||||||
|
node->right = NULL;
|
||||||
|
node->height = 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Record busfault into the correct subtree. */
|
||||||
|
if (node->data > (*tree)->data)
|
||||||
|
RecordBusfault (&(*tree)->right, node);
|
||||||
|
else
|
||||||
|
RecordBusfault (&(*tree)->left, node);
|
||||||
|
|
||||||
|
/* Balance the tree. */
|
||||||
|
RebalanceBusfault (tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Busfault *
|
||||||
|
DetectBusfault (Busfault *tree, char *address)
|
||||||
|
{
|
||||||
|
/* This function is reentrant, but the functions that remove and
|
||||||
|
insert busfaults are not. */
|
||||||
|
|
||||||
|
if (!tree)
|
||||||
|
return NULL;
|
||||||
|
else if (address >= tree->data
|
||||||
|
&& address < tree->data + tree->ignored_area)
|
||||||
|
return tree;
|
||||||
|
|
||||||
|
/* Continue searching in the tree. */
|
||||||
|
if (address > tree->data)
|
||||||
|
/* Search in the right node. */
|
||||||
|
return DetectBusfault (tree->right, address);
|
||||||
|
|
||||||
|
/* Search in the left. */
|
||||||
|
return DetectBusfault (tree->left, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DeleteMin (Busfault **tree, Busfault *out)
|
||||||
|
{
|
||||||
|
Busfault *old_root;
|
||||||
|
|
||||||
|
/* Delete and return the minimum value of the tree. */
|
||||||
|
|
||||||
|
XLAssert (*tree != NULL);
|
||||||
|
|
||||||
|
if (!(*tree)->left)
|
||||||
|
{
|
||||||
|
/* *tree contains the smallest value. */
|
||||||
|
old_root = *tree;
|
||||||
|
out->data = old_root->data;
|
||||||
|
out->ignored_area = old_root->ignored_area;
|
||||||
|
*tree = old_root->right;
|
||||||
|
XLFree (old_root);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Keep looking to the left. */
|
||||||
|
DeleteMin (&(*tree)->left, out);
|
||||||
|
|
||||||
|
RebalanceBusfault (tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RemoveBusfault (Busfault **tree, char *data)
|
||||||
|
{
|
||||||
|
Busfault *old_root;
|
||||||
|
|
||||||
|
if (!*tree)
|
||||||
|
/* There should always be a busfault. */
|
||||||
|
abort ();
|
||||||
|
else if ((*tree)->data == data)
|
||||||
|
{
|
||||||
|
if ((*tree)->right)
|
||||||
|
/* Replace with min value of right subtree. */
|
||||||
|
DeleteMin (&(*tree)->right, *tree);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Splice out old root. */
|
||||||
|
old_root = *tree;
|
||||||
|
*tree = (*tree)->left;
|
||||||
|
XLFree (old_root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (data > (*tree)->data)
|
||||||
|
/* Delete child from the right. */
|
||||||
|
RemoveBusfault (&(*tree)->right, data);
|
||||||
|
else
|
||||||
|
/* Delete from the left. */
|
||||||
|
RemoveBusfault (&(*tree)->left, data);
|
||||||
|
|
||||||
|
RebalanceBusfault (tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
HandleBusfault (int signal, siginfo_t *siginfo, void *ucontext)
|
||||||
|
{
|
||||||
|
/* SIGBUS received. If the faulting address is currently part of a
|
||||||
|
shared memory buffer, ignore. Otherwise, print an error and
|
||||||
|
return. Only reentrant functions must be called within this
|
||||||
|
signal handler. */
|
||||||
|
|
||||||
|
if (DetectBusfault (busfault_tree, siginfo->si_addr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
write (2, "unexpected bus fault\n",
|
||||||
|
sizeof "unexpected bus fault\n");
|
||||||
|
_exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
MaybeInstallBusHandler (void)
|
||||||
|
{
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
|
/* If the SIGBUS handler is already installed, return. */
|
||||||
|
if (bus_handler_installed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bus_handler_installed = 1;
|
||||||
|
memset (&act, 0, sizeof act);
|
||||||
|
|
||||||
|
/* Install a SIGBUS handler. When a client truncates the file
|
||||||
|
backing a shared memory buffer without notifying the compositor,
|
||||||
|
attempting to access the contents of the mapped memory beyond the
|
||||||
|
end of the file will result in SIGBUS being called, which we
|
||||||
|
handle here. */
|
||||||
|
|
||||||
|
act.sa_flags = SA_SIGINFO;
|
||||||
|
act.sa_sigaction = HandleBusfault;
|
||||||
|
|
||||||
|
if (sigaction (SIGBUS, &act, NULL))
|
||||||
|
{
|
||||||
|
perror ("sigaction");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
BlockSigbus (void)
|
||||||
|
{
|
||||||
|
sigset_t sigset;
|
||||||
|
|
||||||
|
sigemptyset (&sigset);
|
||||||
|
sigaddset (&sigset, SIGBUS);
|
||||||
|
|
||||||
|
if (sigprocmask (SIG_BLOCK, &sigset, NULL))
|
||||||
|
{
|
||||||
|
perror ("sigprocmask");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
UnblockSigbus (void)
|
||||||
|
{
|
||||||
|
sigset_t sigset;
|
||||||
|
|
||||||
|
sigemptyset (&sigset);
|
||||||
|
|
||||||
|
if (sigprocmask (SIG_BLOCK, &sigset, NULL))
|
||||||
|
{
|
||||||
|
perror ("sigprocmask");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* These must not overlap. */
|
||||||
|
|
||||||
|
void
|
||||||
|
XLRecordBusfault (void *data, size_t data_size)
|
||||||
|
{
|
||||||
|
Busfault *node;
|
||||||
|
|
||||||
|
MaybeInstallBusHandler ();
|
||||||
|
|
||||||
|
BlockSigbus ();
|
||||||
|
node = XLMalloc (sizeof *node);
|
||||||
|
node->data = data;
|
||||||
|
node->ignored_area = data_size;
|
||||||
|
|
||||||
|
RecordBusfault (&busfault_tree, node);
|
||||||
|
UnblockSigbus ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XLRemoveBusfault (void *data)
|
||||||
|
{
|
||||||
|
BlockSigbus ();
|
||||||
|
RemoveBusfault (&busfault_tree, data);
|
||||||
|
UnblockSigbus ();
|
||||||
|
}
|
||||||
|
|
|
@ -42,8 +42,8 @@ struct _IconSurface
|
||||||
/* The window used by this role. */
|
/* The window used by this role. */
|
||||||
Window window;
|
Window window;
|
||||||
|
|
||||||
/* The picture associated with this role. */
|
/* The rendering target associated with this role. */
|
||||||
Picture picture;
|
RenderTarget target;
|
||||||
|
|
||||||
/* The subcompositor associated with this role. */
|
/* The subcompositor associated with this role. */
|
||||||
Subcompositor *subcompositor;
|
Subcompositor *subcompositor;
|
||||||
|
@ -87,7 +87,7 @@ ReleaseBacking (IconSurface *icon)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Release all allocated resources. */
|
/* Release all allocated resources. */
|
||||||
XRenderFreePicture (compositor.display, icon->picture);
|
RenderDestroyRenderTarget (icon->target);
|
||||||
XDestroyWindow (compositor.display, icon->window);
|
XDestroyWindow (compositor.display, icon->window);
|
||||||
|
|
||||||
/* And the association. */
|
/* And the association. */
|
||||||
|
@ -372,7 +372,6 @@ XLGetIconSurface (Surface *surface)
|
||||||
{
|
{
|
||||||
IconSurface *role;
|
IconSurface *role;
|
||||||
XSetWindowAttributes attrs;
|
XSetWindowAttributes attrs;
|
||||||
XRenderPictureAttributes picture_attrs;
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
role = XLCalloc (1, sizeof *role);
|
role = XLCalloc (1, sizeof *role);
|
||||||
|
@ -410,20 +409,15 @@ XLGetIconSurface (Surface *surface)
|
||||||
PropModeReplace,
|
PropModeReplace,
|
||||||
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
||||||
|
|
||||||
/* Create a picture associated with the window. */
|
/* Create a target associated with the window. */
|
||||||
role->picture = XRenderCreatePicture (compositor.display,
|
role->target = RenderTargetFromWindow (role->window);
|
||||||
role->window,
|
|
||||||
/* TODO: get this from the
|
|
||||||
visual instead. */
|
|
||||||
compositor.argb_format,
|
|
||||||
0, &picture_attrs);
|
|
||||||
|
|
||||||
/* Create a subcompositor associated with the window. */
|
/* Create a subcompositor associated with the window. */
|
||||||
role->subcompositor = MakeSubcompositor ();
|
role->subcompositor = MakeSubcompositor ();
|
||||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||||
|
|
||||||
/* Set the subcompositor target and some callbacks. */
|
/* Set the subcompositor target and some callbacks. */
|
||||||
SubcompositorSetTarget (role->subcompositor, role->picture);
|
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||||
SubcompositorSetBoundsCallback (role->subcompositor,
|
SubcompositorSetBoundsCallback (role->subcompositor,
|
||||||
NoteBounds, role);
|
NoteBounds, role);
|
||||||
|
|
||||||
|
|
|
@ -15,3 +15,12 @@ PIXMANINCLUDES = -I$(INCROOT)/pixman-1
|
||||||
system. */
|
system. */
|
||||||
|
|
||||||
WAYLAND_SCANNER = wayland-scanner
|
WAYLAND_SCANNER = wayland-scanner
|
||||||
|
|
||||||
|
/* Uncomment the following code if building with EGL support.
|
||||||
|
|
||||||
|
#define HaveEglSupport
|
||||||
|
|
||||||
|
EGL = -lEGL
|
||||||
|
GLES = -lGLESv2
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
5
run.c
5
run.c
|
@ -143,8 +143,13 @@ HandleOneXEvent (XEvent *event)
|
||||||
if (XLHandleOneXEventForIconSurfaces (event))
|
if (XLHandleOneXEventForIconSurfaces (event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (XLHandleOneXEventForDmabuf (event))
|
if (XLHandleOneXEventForDmabuf (event))
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (HandleOneXEventForPictureRenderer (event))
|
||||||
|
return;
|
||||||
|
|
||||||
if (XLHandleOneXEventForXData (event))
|
if (XLHandleOneXEventForXData (event))
|
||||||
return;
|
return;
|
||||||
|
|
70
seat.c
70
seat.c
|
@ -513,7 +513,7 @@ struct _DeviceInfo
|
||||||
#define CursorFromRole(role) ((SeatCursor *) (role))
|
#define CursorFromRole(role) ((SeatCursor *) (role))
|
||||||
|
|
||||||
/* Subcompositor targets used inside cursor subframes. */
|
/* Subcompositor targets used inside cursor subframes. */
|
||||||
static Picture cursor_subframe_picture;
|
static RenderTarget cursor_subframe_target;
|
||||||
|
|
||||||
/* Its associated pixmap. */
|
/* Its associated pixmap. */
|
||||||
static Pixmap cursor_subframe_pixmap;
|
static Pixmap cursor_subframe_pixmap;
|
||||||
|
@ -856,22 +856,6 @@ ReleaseSeat (Seat *seat)
|
||||||
XLFree (seat);
|
XLFree (seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Picture
|
|
||||||
PictureForCursor (Drawable drawable)
|
|
||||||
{
|
|
||||||
XRenderPictureAttributes attrs;
|
|
||||||
Picture picture;
|
|
||||||
|
|
||||||
/* This is only required to pacfy -Wmaybe-uninitialized, since
|
|
||||||
valuemask is 0. */
|
|
||||||
memset (&attrs, 0, sizeof attrs);
|
|
||||||
|
|
||||||
picture = XRenderCreatePicture (compositor.display, drawable,
|
|
||||||
compositor.argb_format, 0,
|
|
||||||
&attrs);
|
|
||||||
return picture;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ComputeHotspot (SeatCursor *cursor, int min_x, int min_y,
|
ComputeHotspot (SeatCursor *cursor, int min_x, int min_y,
|
||||||
int *x, int *y)
|
int *x, int *y)
|
||||||
|
@ -899,19 +883,24 @@ ComputeHotspot (SeatCursor *cursor, int min_x, int min_y,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ApplyCursor (SeatCursor *cursor, Picture picture,
|
ApplyCursor (SeatCursor *cursor, RenderTarget target,
|
||||||
int min_x, int min_y)
|
int min_x, int min_y)
|
||||||
{
|
{
|
||||||
Window window;
|
Window window;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
Picture picture;
|
||||||
|
|
||||||
if (cursor->cursor)
|
if (cursor->cursor)
|
||||||
XFreeCursor (compositor.display, cursor->cursor);
|
XFreeCursor (compositor.display, cursor->cursor);
|
||||||
|
|
||||||
ComputeHotspot (cursor, min_x, min_y, &x, &y);
|
ComputeHotspot (cursor, min_x, min_y, &x, &y);
|
||||||
|
|
||||||
|
picture = RenderPictureFromTarget (target);
|
||||||
cursor->cursor = XRenderCreateCursor (compositor.display,
|
cursor->cursor = XRenderCreateCursor (compositor.display,
|
||||||
picture, MAX (0, x),
|
picture, MAX (0, x),
|
||||||
MAX (0, y));
|
MAX (0, y));
|
||||||
|
RenderFreePictureFromTarget (picture);
|
||||||
|
|
||||||
window = CursorWindow (cursor);
|
window = CursorWindow (cursor);
|
||||||
|
|
||||||
if (!(cursor->seat->flags & IsInert) && window != None)
|
if (!(cursor->seat->flags & IsInert) && window != None)
|
||||||
|
@ -923,9 +912,8 @@ ApplyCursor (SeatCursor *cursor, Picture picture,
|
||||||
static void
|
static void
|
||||||
UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
||||||
{
|
{
|
||||||
static XRenderColor empty;
|
|
||||||
Picture picture;
|
|
||||||
Pixmap pixmap;
|
Pixmap pixmap;
|
||||||
|
RenderTarget target;
|
||||||
int min_x, min_y, max_x, max_y, width, height, x, y;
|
int min_x, min_y, max_x, max_y, width, height, x, y;
|
||||||
Bool need_clear;
|
Bool need_clear;
|
||||||
|
|
||||||
|
@ -963,13 +951,12 @@ UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
||||||
pixmap = XCreatePixmap (compositor.display,
|
pixmap = XCreatePixmap (compositor.display,
|
||||||
DefaultRootWindow (compositor.display),
|
DefaultRootWindow (compositor.display),
|
||||||
width, height, compositor.n_planes);
|
width, height, compositor.n_planes);
|
||||||
picture = PictureForCursor (pixmap);
|
target = RenderTargetFromPixmap (pixmap);
|
||||||
|
|
||||||
/* If the bounds extend beyond the subcompositor, clear the
|
/* If the bounds extend beyond the subcompositor, clear the
|
||||||
picture. */
|
picture. */
|
||||||
if (need_clear)
|
if (need_clear)
|
||||||
XRenderFillRectangle (compositor.display, PictOpClear,
|
RenderClearRectangle (target, 0, 0, width, height);
|
||||||
picture, &empty, 0, 0, width, height);
|
|
||||||
|
|
||||||
/* Garbage the subcompositor, since cursor contents are not
|
/* Garbage the subcompositor, since cursor contents are not
|
||||||
preserved. */
|
preserved. */
|
||||||
|
@ -979,13 +966,13 @@ UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
||||||
SubcompositorSetProjectiveTransform (cursor->subcompositor,
|
SubcompositorSetProjectiveTransform (cursor->subcompositor,
|
||||||
MAX (0, -x), MAX (0, -x));
|
MAX (0, -x), MAX (0, -x));
|
||||||
|
|
||||||
SubcompositorSetTarget (cursor->subcompositor, picture);
|
SubcompositorSetTarget (cursor->subcompositor, &target);
|
||||||
SubcompositorUpdate (cursor->subcompositor);
|
SubcompositorUpdate (cursor->subcompositor);
|
||||||
SubcompositorSetTarget (cursor->subcompositor, None);
|
SubcompositorSetTarget (cursor->subcompositor, NULL);
|
||||||
|
|
||||||
ApplyCursor (cursor, picture, min_x, min_y);
|
ApplyCursor (cursor, target, min_x, min_y);
|
||||||
|
|
||||||
XRenderFreePicture (compositor.display, picture);
|
RenderDestroyRenderTarget (target);
|
||||||
XFreePixmap (compositor.display, pixmap);
|
XFreePixmap (compositor.display, pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,8 +1068,7 @@ ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||||
static Bool
|
static Bool
|
||||||
Subframe (Surface *surface, Role *role)
|
Subframe (Surface *surface, Role *role)
|
||||||
{
|
{
|
||||||
static XRenderColor empty;
|
RenderTarget target;
|
||||||
Picture picture;
|
|
||||||
Pixmap pixmap;
|
Pixmap pixmap;
|
||||||
int min_x, min_y, max_x, max_y, width, height, x, y;
|
int min_x, min_y, max_x, max_y, width, height, x, y;
|
||||||
Bool need_clear;
|
Bool need_clear;
|
||||||
|
@ -1129,13 +1115,12 @@ Subframe (Surface *surface, Role *role)
|
||||||
pixmap = XCreatePixmap (compositor.display,
|
pixmap = XCreatePixmap (compositor.display,
|
||||||
DefaultRootWindow (compositor.display),
|
DefaultRootWindow (compositor.display),
|
||||||
width, height, compositor.n_planes);
|
width, height, compositor.n_planes);
|
||||||
picture = PictureForCursor (pixmap);
|
target = RenderTargetFromPixmap (pixmap);
|
||||||
|
|
||||||
/* If the bounds extend beyond the subcompositor, clear the
|
/* If the bounds extend beyond the subcompositor, clear the
|
||||||
picture. */
|
picture. */
|
||||||
if (need_clear)
|
if (need_clear)
|
||||||
XRenderFillRectangle (compositor.display, PictOpClear,
|
RenderClearRectangle (target, 0, 0, width, height);
|
||||||
picture, &empty, 0, 0, width, height);
|
|
||||||
|
|
||||||
/* Garbage the subcompositor, since cursor contents are not
|
/* Garbage the subcompositor, since cursor contents are not
|
||||||
preserved. */
|
preserved. */
|
||||||
|
@ -1144,10 +1129,14 @@ Subframe (Surface *surface, Role *role)
|
||||||
/* Set the right transform if the hotspot is negative. */
|
/* Set the right transform if the hotspot is negative. */
|
||||||
SubcompositorSetProjectiveTransform (cursor->subcompositor,
|
SubcompositorSetProjectiveTransform (cursor->subcompositor,
|
||||||
MAX (0, -x), MAX (0, -x));
|
MAX (0, -x), MAX (0, -x));
|
||||||
SubcompositorSetTarget (cursor->subcompositor, picture);
|
|
||||||
|
|
||||||
/* Set the subframe picture to the picture in question. */
|
/* Attach the rendering target. */
|
||||||
cursor_subframe_picture = picture;
|
SubcompositorSetTarget (cursor->subcompositor, &target);
|
||||||
|
|
||||||
|
/* Set the subframe target and pixmap to the target and pixmap in
|
||||||
|
use. */
|
||||||
|
cursor_subframe_target = target;
|
||||||
|
cursor_subframe_pixmap = pixmap;
|
||||||
|
|
||||||
/* Return True to let the drawing proceed. */
|
/* Return True to let the drawing proceed. */
|
||||||
return True;
|
return True;
|
||||||
|
@ -1161,21 +1150,20 @@ EndSubframe (Surface *surface, Role *role)
|
||||||
|
|
||||||
cursor = CursorFromRole (role);
|
cursor = CursorFromRole (role);
|
||||||
|
|
||||||
if (cursor_subframe_picture)
|
if (cursor_subframe_pixmap != None)
|
||||||
{
|
{
|
||||||
/* First, compute the bounds of the subcompositor. */
|
/* First, compute the bounds of the subcompositor. */
|
||||||
SubcompositorBounds (cursor->subcompositor,
|
SubcompositorBounds (cursor->subcompositor,
|
||||||
&min_x, &min_y, &max_x, &max_y);
|
&min_x, &min_y, &max_x, &max_y);
|
||||||
|
|
||||||
/* Apply the cursor. */
|
/* Apply the cursor. */
|
||||||
ApplyCursor (cursor, cursor_subframe_picture, min_x, min_y);
|
ApplyCursor (cursor, cursor_subframe_target, min_x, min_y);
|
||||||
|
|
||||||
/* Then, free the temporary target. */
|
/* Then, free the temporary target. */
|
||||||
XRenderFreePicture (compositor.display,
|
RenderDestroyRenderTarget (cursor_subframe_target);
|
||||||
cursor_subframe_picture);
|
|
||||||
|
|
||||||
/* Finally, clear the target. */
|
/* Finally, clear the target. */
|
||||||
SubcompositorSetTarget (cursor->subcompositor, None);
|
SubcompositorSetTarget (cursor->subcompositor, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ApplyEmptyCursor (cursor);
|
ApplyEmptyCursor (cursor);
|
||||||
|
@ -1183,6 +1171,8 @@ EndSubframe (Surface *surface, Role *role)
|
||||||
if (cursor_subframe_pixmap)
|
if (cursor_subframe_pixmap)
|
||||||
XFreePixmap (compositor.display,
|
XFreePixmap (compositor.display,
|
||||||
cursor_subframe_pixmap);
|
cursor_subframe_pixmap);
|
||||||
|
|
||||||
|
cursor_subframe_pixmap = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
244
shm.c
244
shm.c
|
@ -21,11 +21,8 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "compositor.h"
|
#include "compositor.h"
|
||||||
|
|
||||||
|
@ -52,24 +49,12 @@ typedef struct _Buffer
|
||||||
/* The ExtBuffer associated with this buffer. */
|
/* The ExtBuffer associated with this buffer. */
|
||||||
ExtBuffer buffer;
|
ExtBuffer buffer;
|
||||||
|
|
||||||
/* The pixmap associated with this buffer. */
|
/* The rendering buffer associated with this buffer. */
|
||||||
Pixmap pixmap;
|
RenderBuffer render_buffer;
|
||||||
|
|
||||||
/* The picture associated with this buffer. */
|
|
||||||
Picture picture;
|
|
||||||
|
|
||||||
/* The width and height of this buffer. */
|
/* The width and height of this buffer. */
|
||||||
unsigned int width, height;
|
unsigned int width, height;
|
||||||
|
|
||||||
/* The stride of this buffer. */
|
|
||||||
int stride;
|
|
||||||
|
|
||||||
/* The offset of this buffer. */
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
/* The format of this buffer. */
|
|
||||||
uint32_t format;
|
|
||||||
|
|
||||||
/* The wl_resource corresponding to this buffer. */
|
/* The wl_resource corresponding to this buffer. */
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
|
|
||||||
|
@ -93,6 +78,14 @@ DereferencePool (Pool *pool)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
munmap (pool->data, pool->size);
|
munmap (pool->data, pool->size);
|
||||||
|
|
||||||
|
/* Cancel the busfault trap. */
|
||||||
|
|
||||||
|
if (pool->data != (void *) -1
|
||||||
|
/* If the pool is of size 0, no busfault was installed. */
|
||||||
|
&& pool->size)
|
||||||
|
XLRemoveBusfault (pool->data);
|
||||||
|
|
||||||
close (pool->fd);
|
close (pool->fd);
|
||||||
XLFree (pool);
|
XLFree (pool);
|
||||||
}
|
}
|
||||||
|
@ -115,8 +108,7 @@ DereferenceBuffer (Buffer *buffer)
|
||||||
if (--buffer->refcount)
|
if (--buffer->refcount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XRenderFreePicture (compositor.display, buffer->picture);
|
RenderFreeShmBuffer (buffer->render_buffer);
|
||||||
XFreePixmap (compositor.display, buffer->pixmap);
|
|
||||||
DereferencePool (buffer->pool);
|
DereferencePool (buffer->pool);
|
||||||
|
|
||||||
ExtBufferDestroy (&buffer->buffer);
|
ExtBufferDestroy (&buffer->buffer);
|
||||||
|
@ -142,16 +134,10 @@ DereferenceBufferFunc (ExtBuffer *buffer)
|
||||||
DereferenceBuffer ((Buffer *) buffer);
|
DereferenceBuffer ((Buffer *) buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Picture
|
static RenderBuffer
|
||||||
GetPictureFunc (ExtBuffer *buffer)
|
GetBufferFunc (ExtBuffer *buffer)
|
||||||
{
|
{
|
||||||
return ((Buffer *) buffer)->picture;
|
return ((Buffer *) buffer)->render_buffer;
|
||||||
}
|
|
||||||
|
|
||||||
static Pixmap
|
|
||||||
GetPixmapFunc (ExtBuffer *buffer)
|
|
||||||
{
|
|
||||||
return ((Buffer *) buffer)->pixmap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
|
@ -175,20 +161,7 @@ DestroyBuffer (struct wl_client *client, struct wl_resource *resource)
|
||||||
static void
|
static void
|
||||||
PrintBuffer (Buffer *buffer)
|
PrintBuffer (Buffer *buffer)
|
||||||
{
|
{
|
||||||
int x, y;
|
/* Not implemented. */
|
||||||
char *base;
|
|
||||||
unsigned int *base32;
|
|
||||||
|
|
||||||
for (y = 0; y < buffer->height; ++y)
|
|
||||||
{
|
|
||||||
base = buffer->pool->data;
|
|
||||||
base += buffer->stride * y;
|
|
||||||
base32 = (unsigned int *) base;
|
|
||||||
|
|
||||||
for (x = 0; x < buffer->width; ++x)
|
|
||||||
fprintf (stderr, "#x%8x ", base32[x]);
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -197,37 +170,6 @@ PrintBufferFunc (ExtBuffer *buffer)
|
||||||
PrintBuffer ((Buffer *) buffer);
|
PrintBuffer ((Buffer *) buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
DepthForFormat (uint32_t format)
|
|
||||||
{
|
|
||||||
switch (format)
|
|
||||||
{
|
|
||||||
case WL_SHM_FORMAT_ARGB8888:
|
|
||||||
return 32;
|
|
||||||
|
|
||||||
case WL_SHM_FORMAT_XRGB8888:
|
|
||||||
return 24;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static XRenderPictFormat *
|
|
||||||
PictFormatForFormat (uint32_t format)
|
|
||||||
{
|
|
||||||
switch (format)
|
|
||||||
{
|
|
||||||
case WL_SHM_FORMAT_ARGB8888:
|
|
||||||
return compositor.argb_format;
|
|
||||||
|
|
||||||
case WL_SHM_FORMAT_XRGB8888:
|
|
||||||
return compositor.xrgb_format;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
HandleBufferResourceDestroy (struct wl_resource *resource)
|
HandleBufferResourceDestroy (struct wl_resource *resource)
|
||||||
|
@ -245,22 +187,35 @@ static const struct wl_buffer_interface wl_shm_buffer_impl =
|
||||||
.destroy = DestroyBuffer,
|
.destroy = DestroyBuffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
IsFormatSupported (uint32_t format)
|
||||||
|
{
|
||||||
|
ShmFormat *formats;
|
||||||
|
int nformats, i;
|
||||||
|
|
||||||
|
formats = RenderGetShmFormats (&nformats);
|
||||||
|
|
||||||
|
for (i = 0; i < nformats; ++i)
|
||||||
|
{
|
||||||
|
if (formats[i].format == format)
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
||||||
uint32_t id, int32_t offset, int32_t width, int32_t height,
|
uint32_t id, int32_t offset, int32_t width, int32_t height,
|
||||||
int32_t stride, uint32_t format)
|
int32_t stride, uint32_t format)
|
||||||
{
|
{
|
||||||
XRenderPictureAttributes picture_attrs;
|
|
||||||
Pool *pool;
|
Pool *pool;
|
||||||
Buffer *buffer;
|
Buffer *buffer;
|
||||||
xcb_shm_seg_t seg;
|
RenderBuffer render_buffer;
|
||||||
Pixmap pixmap;
|
SharedMemoryAttributes attrs;
|
||||||
Picture picture;
|
Bool failure;
|
||||||
int fd, depth;
|
|
||||||
|
|
||||||
depth = DepthForFormat (format);
|
if (!IsFormatSupported (format))
|
||||||
|
|
||||||
if (!depth)
|
|
||||||
{
|
{
|
||||||
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FORMAT,
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FORMAT,
|
||||||
"the specified format is not supported");
|
"the specified format is not supported");
|
||||||
|
@ -269,9 +224,8 @@ CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
||||||
|
|
||||||
pool = wl_resource_get_user_data (resource);
|
pool = wl_resource_get_user_data (resource);
|
||||||
|
|
||||||
if (pool->size < offset || stride != width * 4
|
if (!RenderValidateShmParams (format, width, height,
|
||||||
|| offset + stride * height > pool->size
|
offset, stride, pool->size))
|
||||||
|| offset < 0)
|
|
||||||
{
|
{
|
||||||
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_STRIDE,
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_STRIDE,
|
||||||
"invalid offset or stride, or pool too small");
|
"invalid offset or stride, or pool too small");
|
||||||
|
@ -314,46 +268,43 @@ CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XCB closes fds after sending them. */
|
attrs.format = format;
|
||||||
fd = fcntl (pool->fd, F_DUPFD_CLOEXEC, 0);
|
attrs.offset = offset;
|
||||||
|
attrs.width = width;
|
||||||
|
attrs.height = height;
|
||||||
|
attrs.stride = stride;
|
||||||
|
attrs.fd = pool->fd;
|
||||||
|
|
||||||
if (fd < 0)
|
/* Pass a reference instead of the pointer itself. The pool will
|
||||||
|
stay valid as long as the buffer is still alive, and the data
|
||||||
|
pointer can change if the client resizes the pool. */
|
||||||
|
attrs.data = &pool->data;
|
||||||
|
attrs.pool_size = pool->size;
|
||||||
|
|
||||||
|
/* Now, create the renderer buffer. */
|
||||||
|
failure = False;
|
||||||
|
render_buffer = RenderBufferFromShm (&attrs, &failure);
|
||||||
|
|
||||||
|
/* If a platform specific error happened, fail now. */
|
||||||
|
if (failure)
|
||||||
{
|
{
|
||||||
wl_resource_destroy (buffer->resource);
|
wl_resource_destroy (buffer->resource);
|
||||||
XLFree (buffer);
|
XLFree (buffer);
|
||||||
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
||||||
"fcntl: %s", strerror (errno));
|
"unknown error creating buffer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
seg = xcb_generate_id (compositor.conn);
|
buffer->render_buffer = render_buffer;
|
||||||
pixmap = xcb_generate_id (compositor.conn);
|
|
||||||
|
|
||||||
xcb_shm_attach_fd (compositor.conn, seg, fd, false);
|
|
||||||
xcb_shm_create_pixmap (compositor.conn, pixmap,
|
|
||||||
DefaultRootWindow (compositor.display),
|
|
||||||
width, height, depth, seg, offset);
|
|
||||||
xcb_shm_detach (compositor.conn, seg);
|
|
||||||
|
|
||||||
picture = XRenderCreatePicture (compositor.display, pixmap,
|
|
||||||
PictFormatForFormat (format),
|
|
||||||
0, &picture_attrs);
|
|
||||||
|
|
||||||
buffer->pixmap = pixmap;
|
|
||||||
buffer->picture = picture;
|
|
||||||
buffer->width = width;
|
buffer->width = width;
|
||||||
buffer->height = height;
|
buffer->height = height;
|
||||||
buffer->stride = stride;
|
|
||||||
buffer->offset = offset;
|
|
||||||
buffer->format = format;
|
|
||||||
buffer->pool = pool;
|
buffer->pool = pool;
|
||||||
buffer->refcount = 1;
|
buffer->refcount = 1;
|
||||||
|
|
||||||
/* Initialize function pointers. */
|
/* Initialize function pointers. */
|
||||||
buffer->buffer.funcs.retain = RetainBufferFunc;
|
buffer->buffer.funcs.retain = RetainBufferFunc;
|
||||||
buffer->buffer.funcs.dereference = DereferenceBufferFunc;
|
buffer->buffer.funcs.dereference = DereferenceBufferFunc;
|
||||||
buffer->buffer.funcs.get_picture = GetPictureFunc;
|
buffer->buffer.funcs.get_buffer = GetBufferFunc;
|
||||||
buffer->buffer.funcs.get_pixmap = GetPixmapFunc;
|
|
||||||
buffer->buffer.funcs.width = WidthFunc;
|
buffer->buffer.funcs.width = WidthFunc;
|
||||||
buffer->buffer.funcs.height = HeightFunc;
|
buffer->buffer.funcs.height = HeightFunc;
|
||||||
buffer->buffer.funcs.release = ReleaseBufferFunc;
|
buffer->buffer.funcs.release = ReleaseBufferFunc;
|
||||||
|
@ -390,6 +341,19 @@ ResizePool (struct wl_client *client, struct wl_resource *resource,
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
pool = wl_resource_get_user_data (resource);
|
pool = wl_resource_get_user_data (resource);
|
||||||
|
|
||||||
|
if (size == pool->size)
|
||||||
|
/* There is no need to do anything, since the pool is still the
|
||||||
|
same size. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (size < pool->size)
|
||||||
|
{
|
||||||
|
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
||||||
|
"shared memory pools cannot be shrunk");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data = mremap (pool->data, pool->size, size, MREMAP_MAYMOVE);
|
data = mremap (pool->data, pool->size, size, MREMAP_MAYMOVE);
|
||||||
|
|
||||||
if (data == MAP_FAILED)
|
if (data == MAP_FAILED)
|
||||||
|
@ -399,8 +363,17 @@ ResizePool (struct wl_client *client, struct wl_resource *resource,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now cancel the existing bus fault handler, should it have been
|
||||||
|
installed. */
|
||||||
|
if (pool->size)
|
||||||
|
XLRemoveBusfault (pool->data);
|
||||||
|
|
||||||
pool->size = size;
|
pool->size = size;
|
||||||
pool->data = data;
|
pool->data = data;
|
||||||
|
|
||||||
|
/* And add a new handler. */
|
||||||
|
if (pool->size)
|
||||||
|
XLRecordBusfault (pool->data, pool->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_shm_pool_interface wl_shm_pool_impl =
|
static const struct wl_shm_pool_interface wl_shm_pool_impl =
|
||||||
|
@ -417,9 +390,8 @@ HandleResourceDestroy (struct wl_resource *resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CreatePool (struct wl_client *client,
|
CreatePool (struct wl_client *client, struct wl_resource *resource,
|
||||||
struct wl_resource *resource,
|
uint32_t id, int32_t fd, int32_t size)
|
||||||
uint32_t id, int fd, int size)
|
|
||||||
{
|
{
|
||||||
Pool *pool;
|
Pool *pool;
|
||||||
|
|
||||||
|
@ -459,6 +431,13 @@ CreatePool (struct wl_client *client,
|
||||||
pool, HandlePoolResourceDestroy);
|
pool, HandlePoolResourceDestroy);
|
||||||
|
|
||||||
pool->size = size;
|
pool->size = size;
|
||||||
|
|
||||||
|
/* Begin trapping SIGBUS from this pool. The client may truncate
|
||||||
|
the file without telling us, in which case accessing its contents
|
||||||
|
will cause crashes. */
|
||||||
|
if (pool->size)
|
||||||
|
XLRecordBusfault (pool->data, pool->size);
|
||||||
|
|
||||||
pool->fd = fd;
|
pool->fd = fd;
|
||||||
pool->refcount = 1;
|
pool->refcount = 1;
|
||||||
|
|
||||||
|
@ -473,10 +452,13 @@ static const struct wl_shm_interface wl_shm_impl =
|
||||||
static void
|
static void
|
||||||
PostFormats (struct wl_resource *resource)
|
PostFormats (struct wl_resource *resource)
|
||||||
{
|
{
|
||||||
/* TODO: don't hard-code visuals and be slightly more versatile. */
|
ShmFormat *formats;
|
||||||
|
int nformats, i;
|
||||||
|
|
||||||
wl_shm_send_format (resource, WL_SHM_FORMAT_XRGB8888);
|
formats = RenderGetShmFormats (&nformats);
|
||||||
wl_shm_send_format (resource, WL_SHM_FORMAT_ARGB8888);
|
|
||||||
|
for (i = 0; i < nformats; ++i)
|
||||||
|
wl_shm_send_format (resource, formats[i].format);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -544,40 +526,6 @@ InitRender (void)
|
||||||
void
|
void
|
||||||
XLInitShm (void)
|
XLInitShm (void)
|
||||||
{
|
{
|
||||||
xcb_shm_query_version_reply_t *reply;
|
|
||||||
xcb_shm_query_version_cookie_t cookie;
|
|
||||||
|
|
||||||
/* This shouldn't be freed. */
|
|
||||||
const xcb_query_extension_reply_t *ext;
|
|
||||||
|
|
||||||
ext = xcb_get_extension_data (compositor.conn, &xcb_shm_id);
|
|
||||||
|
|
||||||
if (!ext || !ext->present)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "The MIT-SHM extension is not supported by this X server.\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie = xcb_shm_query_version (compositor.conn);
|
|
||||||
reply = xcb_shm_query_version_reply (compositor.conn,
|
|
||||||
cookie, NULL);
|
|
||||||
|
|
||||||
if (!reply)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "The MIT-SHM extension on this X server is too old.\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
else if (reply->major_version < 1
|
|
||||||
|| (reply->major_version == 1
|
|
||||||
&& reply->minor_version < 2))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "The MIT-SHM extension on this X server is too old"
|
|
||||||
" to support POSIX shared memory.\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
free (reply);
|
|
||||||
|
|
||||||
InitRender ();
|
InitRender ();
|
||||||
|
|
||||||
global_shm = wl_global_create (compositor.wl_display,
|
global_shm = wl_global_create (compositor.wl_display,
|
||||||
|
|
496
subcompositor.c
496
subcompositor.c
|
@ -139,19 +139,21 @@ enum
|
||||||
{
|
{
|
||||||
/* This means that the view hierarchy has changed, and all
|
/* This means that the view hierarchy has changed, and all
|
||||||
subcompositing optimisations should be skipped. */
|
subcompositing optimisations should be skipped. */
|
||||||
SubcompositorIsGarbaged = 1,
|
SubcompositorIsGarbaged = 1,
|
||||||
/* This means that the opaque region of one of the views
|
/* This means that the opaque region of one of the views
|
||||||
changed. */
|
changed. */
|
||||||
SubcompositorIsOpaqueDirty = (1 << 2),
|
SubcompositorIsOpaqueDirty = (1 << 2),
|
||||||
/* This means that the input region of one of the views
|
/* This means that the input region of one of the views
|
||||||
changed. */
|
changed. */
|
||||||
SubcompositorIsInputDirty = (1 << 3),
|
SubcompositorIsInputDirty = (1 << 3),
|
||||||
/* This means that there is at least one unmapped view in this
|
/* This means that there is at least one unmapped view in this
|
||||||
subcompositor. */
|
subcompositor. */
|
||||||
SubcompositorIsPartiallyMapped = (1 << 4),
|
SubcompositorIsPartiallyMapped = (1 << 4),
|
||||||
/* This means that the subcompositor is frozen and updates should
|
/* This means that the subcompositor is frozen and updates should
|
||||||
do nothing. */
|
do nothing. */
|
||||||
SubcompositorIsFrozen = (1 << 5),
|
SubcompositorIsFrozen = (1 << 5),
|
||||||
|
/* This means that the subcompositor has a target attached. */
|
||||||
|
SubcompositorIsTargetAttached = (1 << 6),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IsGarbaged(subcompositor) \
|
#define IsGarbaged(subcompositor) \
|
||||||
|
@ -179,6 +181,11 @@ enum
|
||||||
#define IsFrozen(subcompositor) \
|
#define IsFrozen(subcompositor) \
|
||||||
((subcompositor)->state & SubcompositorIsFrozen)
|
((subcompositor)->state & SubcompositorIsFrozen)
|
||||||
|
|
||||||
|
#define SetTargetAttached(subcompositor) \
|
||||||
|
((subcompositor)->state |= SubcompositorIsTargetAttached)
|
||||||
|
#define IsTargetAttached(subcompositor) \
|
||||||
|
((subcompositor)->state & SubcompositorIsTargetAttached)
|
||||||
|
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -218,11 +225,6 @@ struct _View
|
||||||
into a compositor. */
|
into a compositor. */
|
||||||
Subcompositor *subcompositor;
|
Subcompositor *subcompositor;
|
||||||
|
|
||||||
#ifndef TEST
|
|
||||||
/* Picture this subcompositor draws to. */
|
|
||||||
Picture picture;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Pointer to the parent view. NULL if the parent is the
|
/* Pointer to the parent view. NULL if the parent is the
|
||||||
subcompositor itself. */
|
subcompositor itself. */
|
||||||
View *parent;
|
View *parent;
|
||||||
|
@ -289,8 +291,8 @@ struct _Subcompositor
|
||||||
List *children, *last_children;
|
List *children, *last_children;
|
||||||
|
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
/* The picture that is rendered to. */
|
/* Target this subcompositor draws to. */
|
||||||
Picture target;
|
RenderTarget target;
|
||||||
|
|
||||||
/* Function called when the opaque region changes. */
|
/* Function called when the opaque region changes. */
|
||||||
void (*opaque_change) (Subcompositor *, void *,
|
void (*opaque_change) (Subcompositor *, void *,
|
||||||
|
@ -316,6 +318,14 @@ struct _Subcompositor
|
||||||
|
|
||||||
/* An additional offset to apply when drawing to the target. */
|
/* An additional offset to apply when drawing to the target. */
|
||||||
int tx, ty;
|
int tx, ty;
|
||||||
|
|
||||||
|
/* Buffers used to store that damage. */
|
||||||
|
pixman_region32_t prior_damage[2];
|
||||||
|
|
||||||
|
/* The damage region of previous updates. last_damage is what the
|
||||||
|
damage region was 1 update ago, and before_damage is what the
|
||||||
|
damage region was 2 updates ago. */
|
||||||
|
pixman_region32_t *last_damage, *before_damage;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -330,10 +340,6 @@ enum
|
||||||
DoAll = 0xf,
|
DoAll = 0xf,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The identity transform. */
|
|
||||||
|
|
||||||
static XTransform identity_transform;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -411,6 +417,10 @@ MakeSubcompositor (void)
|
||||||
subcompositor->last = subcompositor->inferiors;
|
subcompositor->last = subcompositor->inferiors;
|
||||||
subcompositor->last_children = subcompositor->children;
|
subcompositor->last_children = subcompositor->children;
|
||||||
|
|
||||||
|
/* Initialize the buffers used to store previous damage. */
|
||||||
|
pixman_region32_init (&subcompositor->prior_damage[0]);
|
||||||
|
pixman_region32_init (&subcompositor->prior_damage[1]);
|
||||||
|
|
||||||
return subcompositor;
|
return subcompositor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,9 +572,16 @@ SubcompositorUpdateBoundsForInsert (Subcompositor *subcompositor,
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
|
|
||||||
void
|
void
|
||||||
SubcompositorSetTarget (Subcompositor *compositor, Picture picture)
|
SubcompositorSetTarget (Subcompositor *compositor,
|
||||||
|
RenderTarget *target_in)
|
||||||
{
|
{
|
||||||
compositor->target = picture;
|
if (target_in)
|
||||||
|
{
|
||||||
|
compositor->target = *target_in;
|
||||||
|
SetTargetAttached (compositor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
compositor->state &= SubcompositorIsTargetAttached;
|
||||||
|
|
||||||
/* We don't know if the new picture has the previous state left
|
/* We don't know if the new picture has the previous state left
|
||||||
over. */
|
over. */
|
||||||
|
@ -1171,6 +1188,19 @@ main (int argc, char **argv)
|
||||||
the target drawable. Afterwards, the damage region of each
|
the target drawable. Afterwards, the damage region of each
|
||||||
inferior is cleared, and the process can begin again.
|
inferior is cleared, and the process can begin again.
|
||||||
|
|
||||||
|
However, under some situations, the contents of the target drawable
|
||||||
|
may reflect what was drawn two or three invocations of
|
||||||
|
SubcompositorUpdate ago. To enable efficient updates when that is
|
||||||
|
the case, the subcompositor will keep track of the global damage
|
||||||
|
regions of the past two updates, and intersect the resulting global
|
||||||
|
damage region of each invocation with the appropriate number of
|
||||||
|
previous regions.
|
||||||
|
|
||||||
|
For simplicity's sake, the update inferior is reset to the first
|
||||||
|
view in the subcompositor's inferior list whenever the global
|
||||||
|
damage region is intersected with the damage region of a previous
|
||||||
|
update.
|
||||||
|
|
||||||
Such computation is not reliable, however, if the size or position
|
Such computation is not reliable, however, if the size or position
|
||||||
of a view changes. In the interest of keeping thing simple, every
|
of a view changes. In the interest of keeping thing simple, every
|
||||||
inferior is composited onto the target drawable whenever a view
|
inferior is composited onto the target drawable whenever a view
|
||||||
|
@ -1560,21 +1590,10 @@ GetTxTy (int scale)
|
||||||
return 1.0 / (-scale + 1);
|
return 1.0 / (-scale + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static XTransform
|
static void
|
||||||
ViewGetTransform (View *view)
|
ViewApplyTransform (View *view, RenderBuffer buffer)
|
||||||
{
|
{
|
||||||
XTransform transform;
|
RenderApplyTransform (buffer, GetTxTy (view->scale));
|
||||||
double transform_value;
|
|
||||||
|
|
||||||
/* Perform scaling in the transform matrix. */
|
|
||||||
|
|
||||||
memset (&transform, 0, sizeof transform);
|
|
||||||
transform_value = GetTxTy (view->scale);
|
|
||||||
transform.matrix[0][0] = XDoubleToFixed (transform_value);
|
|
||||||
transform.matrix[1][1] = XDoubleToFixed (transform_value);
|
|
||||||
transform.matrix[2][2] = XDoubleToFixed (1);
|
|
||||||
|
|
||||||
return transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: the callers of this can be optimized by setting the picture
|
/* TODO: the callers of this can be optimized by setting the picture
|
||||||
|
@ -1625,31 +1644,9 @@ static void
|
||||||
FillBoxesWithTransparency (Subcompositor *subcompositor,
|
FillBoxesWithTransparency (Subcompositor *subcompositor,
|
||||||
pixman_box32_t *boxes, int nboxes)
|
pixman_box32_t *boxes, int nboxes)
|
||||||
{
|
{
|
||||||
XRectangle *rects;
|
RenderFillBoxesWithTransparency (subcompositor->target, boxes,
|
||||||
static XRenderColor color;
|
nboxes, subcompositor->min_x,
|
||||||
int i;
|
subcompositor->min_y);
|
||||||
Picture picture;
|
|
||||||
|
|
||||||
picture = subcompositor->target;
|
|
||||||
|
|
||||||
if (nboxes < 256)
|
|
||||||
rects = alloca (sizeof *rects * nboxes);
|
|
||||||
else
|
|
||||||
rects = XLMalloc (sizeof *rects * nboxes);
|
|
||||||
|
|
||||||
for (i = 0; i < nboxes; ++i)
|
|
||||||
{
|
|
||||||
rects[i].x = BoxStartX (boxes[i]) - subcompositor->min_x;
|
|
||||||
rects[i].y = BoxStartY (boxes[i]) - subcompositor->min_y;
|
|
||||||
rects[i].width = BoxWidth (boxes[i]);
|
|
||||||
rects[i].height = BoxHeight (boxes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
XRenderFillRectangles (compositor.display, PictOpClear, picture,
|
|
||||||
&color, rects, nboxes);
|
|
||||||
|
|
||||||
if (nboxes >= 256)
|
|
||||||
XLFree (rects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
|
@ -1684,6 +1681,52 @@ SubcompositorIsEmpty (Subcompositor *subcompositor)
|
||||||
&& subcompositor->min_y == subcompositor->max_y);
|
&& subcompositor->min_y == subcompositor->max_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
StorePreviousDamage (Subcompositor *subcompositor,
|
||||||
|
pixman_region32_t *update_region)
|
||||||
|
{
|
||||||
|
pixman_region32_t *prior;
|
||||||
|
|
||||||
|
if (renderer_flags & NeverAges)
|
||||||
|
/* Aging never happens, so recording prior damage is
|
||||||
|
unnecessary. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Move last_damage to prior_damage if it already exists, and find
|
||||||
|
something to hold more damage and set it as last_damage. There
|
||||||
|
is no need to do this if the render target age never exceeds
|
||||||
|
0. */
|
||||||
|
|
||||||
|
if (!subcompositor->last_damage)
|
||||||
|
subcompositor->last_damage = &subcompositor->prior_damage[0];
|
||||||
|
else if (!subcompositor->before_damage)
|
||||||
|
{
|
||||||
|
subcompositor->before_damage = subcompositor->last_damage;
|
||||||
|
subcompositor->last_damage = &subcompositor->prior_damage[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prior = subcompositor->before_damage;
|
||||||
|
subcompositor->before_damage = subcompositor->last_damage;
|
||||||
|
subcompositor->last_damage = prior;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL means use the bounds of the subcompositor. */
|
||||||
|
if (!update_region)
|
||||||
|
{
|
||||||
|
pixman_region32_fini (subcompositor->last_damage);
|
||||||
|
pixman_region32_init_rect (subcompositor->last_damage,
|
||||||
|
subcompositor->min_x,
|
||||||
|
subcompositor->min_y,
|
||||||
|
subcompositor->max_x,
|
||||||
|
subcompositor->max_y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Copy the update region to last_damage. */
|
||||||
|
pixman_region32_copy (subcompositor->last_damage,
|
||||||
|
update_region);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SubcompositorUpdate (Subcompositor *subcompositor)
|
SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
{
|
{
|
||||||
|
@ -1692,13 +1735,14 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
View *start, *original_start, *view, *first;
|
View *start, *original_start, *view, *first;
|
||||||
List *list;
|
List *list;
|
||||||
pixman_box32_t *boxes, *extents, temp_boxes;
|
pixman_box32_t *boxes, *extents, temp_boxes;
|
||||||
int nboxes, i, op, tx, ty;
|
int nboxes, i, tx, ty;
|
||||||
Picture picture;
|
Operation op;
|
||||||
XTransform transform;
|
RenderBuffer buffer;
|
||||||
int min_x, min_y;
|
int min_x, min_y;
|
||||||
|
int age;
|
||||||
|
|
||||||
/* Just return if no target was specified. */
|
/* Just return if no target was specified. */
|
||||||
if (subcompositor->target == None)
|
if (!IsTargetAttached (subcompositor))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Likewise if the subcompositor is "frozen". */
|
/* Likewise if the subcompositor is "frozen". */
|
||||||
|
@ -1717,6 +1761,31 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
start = subcompositor->inferiors->next->view;
|
start = subcompositor->inferiors->next->view;
|
||||||
original_start = subcompositor->inferiors->next->view;
|
original_start = subcompositor->inferiors->next->view;
|
||||||
|
age = RenderTargetAge (subcompositor->target);
|
||||||
|
|
||||||
|
/* If there is not enough prior damage available to satisfy age, set
|
||||||
|
it to -1. */
|
||||||
|
|
||||||
|
if (age > 0 && !subcompositor->last_damage)
|
||||||
|
age = -1;
|
||||||
|
|
||||||
|
if (age > 2 && !subcompositor->before_damage)
|
||||||
|
age = -1;
|
||||||
|
|
||||||
|
/* If the subcompositor is garbaged, clear all prior damage. */
|
||||||
|
if (IsGarbaged (subcompositor))
|
||||||
|
{
|
||||||
|
if (subcompositor->last_damage)
|
||||||
|
pixman_region32_clear (subcompositor->last_damage);
|
||||||
|
|
||||||
|
if (subcompositor->before_damage)
|
||||||
|
pixman_region32_clear (subcompositor->before_damage);
|
||||||
|
|
||||||
|
/* Reset these fields to NULL, so we do not try to use them
|
||||||
|
later on. */
|
||||||
|
subcompositor->last_damage = NULL;
|
||||||
|
subcompositor->before_damage = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear the "is partially mapped" flag. It will be set later on if
|
/* Clear the "is partially mapped" flag. It will be set later on if
|
||||||
there is actually a partially mapped view. */
|
there is actually a partially mapped view. */
|
||||||
|
@ -1727,7 +1796,17 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
min_x, min_y, subcompositor->max_x,
|
min_x, min_y, subcompositor->max_x,
|
||||||
subcompositor->max_y);
|
subcompositor->max_y);
|
||||||
|
|
||||||
if (!IsGarbaged (subcompositor))
|
/* Note the size of this subcompositor, so the viewport can be set
|
||||||
|
accordingly. */
|
||||||
|
RenderNoteTargetSize (subcompositor->target,
|
||||||
|
subcompositor->max_x - min_x + 1,
|
||||||
|
subcompositor->max_y - min_y + 1);
|
||||||
|
|
||||||
|
if (!IsGarbaged (subcompositor)
|
||||||
|
/* If the target contents are too old or invalid, we go down the
|
||||||
|
usual IsGarbaged code path, except we do not recompute the
|
||||||
|
input or opaque regions unless they are dirty. */
|
||||||
|
&& (age >= 0 && age < 3))
|
||||||
{
|
{
|
||||||
start = NULL;
|
start = NULL;
|
||||||
original_start = NULL;
|
original_start = NULL;
|
||||||
|
@ -1793,8 +1872,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
&update_region, &temp);
|
&update_region, &temp);
|
||||||
|
|
||||||
/* This view will obscure all preceding damaged areas,
|
/* This view will obscure all preceding damaged areas,
|
||||||
so make start here. */
|
so make start here. This optimization is disabled if
|
||||||
if (!pixman_region32_not_empty (&update_region))
|
the target contents are too old, as prior damage
|
||||||
|
could reveal contents below. */
|
||||||
|
if (!pixman_region32_not_empty (&update_region) && !age)
|
||||||
{
|
{
|
||||||
start = list->view;
|
start = list->view;
|
||||||
|
|
||||||
|
@ -1834,6 +1915,14 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
if (pixman_region32_not_empty (&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
|
/* Translate the region into the subcompositor
|
||||||
coordinate space. */
|
coordinate space. */
|
||||||
pixman_region32_translate (&list->view->damage,
|
pixman_region32_translate (&list->view->damage,
|
||||||
|
@ -1906,13 +1995,48 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini (&start_opaque);
|
pixman_region32_fini (&start_opaque);
|
||||||
|
|
||||||
|
/* First store previous damage. */
|
||||||
|
StorePreviousDamage (subcompositor, &update_region);
|
||||||
|
|
||||||
|
/* Now, apply any prior damage that might be required. */
|
||||||
|
if (age > 0)
|
||||||
|
pixman_region32_union (&update_region, &update_region,
|
||||||
|
/* This is checked to exist upon
|
||||||
|
entering this code path. */
|
||||||
|
subcompositor->last_damage);
|
||||||
|
|
||||||
|
if (age > 1)
|
||||||
|
pixman_region32_union (&update_region, &update_region,
|
||||||
|
/* This is checked to exist upon
|
||||||
|
entering this code path. */
|
||||||
|
subcompositor->before_damage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* To save from iterating over all the views twice, perform the
|
/* To save from iterating over all the views twice, perform the
|
||||||
input and opaque region updates in the draw loop instead. */
|
input and opaque region updates in the draw loop instead. */
|
||||||
pixman_region32_init (&total_opaque);
|
|
||||||
pixman_region32_init (&total_input);
|
if (IsGarbaged (subcompositor))
|
||||||
|
{
|
||||||
|
pixman_region32_init (&total_opaque);
|
||||||
|
pixman_region32_init (&total_input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we are in the IsGarbaged code because the
|
||||||
|
target contents are too old. Only initialize the opaque
|
||||||
|
and input regions if they are dirty. */
|
||||||
|
|
||||||
|
if (IsOpaqueDirty (subcompositor))
|
||||||
|
pixman_region32_init (&total_opaque);
|
||||||
|
|
||||||
|
if (IsInputDirty (subcompositor))
|
||||||
|
pixman_region32_init (&total_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either way, put something in the prior damage ring. */
|
||||||
|
StorePreviousDamage (subcompositor, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there's nothing to do, return. */
|
/* If there's nothing to do, return. */
|
||||||
|
@ -1925,6 +2049,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
list = start->link;
|
list = start->link;
|
||||||
first = NULL;
|
first = NULL;
|
||||||
|
|
||||||
|
/* Begin rendering. This is unnecessary on XRender, but required on
|
||||||
|
EGL to make the surface current and set the viewport. */
|
||||||
|
RenderStartRender (subcompositor->target);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
view = list->view;
|
view = list->view;
|
||||||
|
@ -1947,7 +2075,24 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
if (!view->buffer)
|
if (!view->buffer)
|
||||||
goto next_1;
|
goto next_1;
|
||||||
|
|
||||||
picture = XLPictureFromBuffer (view->buffer);
|
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||||
|
|
||||||
|
if (IsGarbaged (subcompositor))
|
||||||
|
/* 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.
|
||||||
|
|
||||||
|
As the damage cannot be trusted while the subcompositor is
|
||||||
|
update, pass NULL; this tells the renderer to update the
|
||||||
|
entire buffer.
|
||||||
|
|
||||||
|
Note that if the subcompositor is not garbaged, then this
|
||||||
|
has already been done. */
|
||||||
|
RenderUpdateBufferForDamage (buffer, NULL);
|
||||||
|
else if (age < 0 || age > 3)
|
||||||
|
/* The target contents are too old, but the damage can be
|
||||||
|
trusted. */
|
||||||
|
RenderUpdateBufferForDamage (buffer, &view->damage);
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
|
@ -1955,7 +2100,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
with PictOpSrc so that transparency is applied correctly,
|
with PictOpSrc so that transparency is applied correctly,
|
||||||
if it contains the entire update region. */
|
if it contains the entire update region. */
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor))
|
if (IsGarbaged (subcompositor) || age < 0 || age > 3)
|
||||||
{
|
{
|
||||||
extents = &temp_boxes;
|
extents = &temp_boxes;
|
||||||
|
|
||||||
|
@ -1971,14 +2116,14 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
if (ViewContainsExtents (view, extents))
|
if (ViewContainsExtents (view, extents))
|
||||||
/* The update region is contained by the entire view, so
|
/* The update region is contained by the entire view, so
|
||||||
use PictOpSrc. */
|
use source. */
|
||||||
op = PictOpSrc;
|
op = OperationSource;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Otherwise, fill the whole update region with
|
/* Otherwise, fill the whole update region with
|
||||||
transparency. */
|
transparency. */
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor))
|
if (IsGarbaged (subcompositor) || age < 0 || age > 3)
|
||||||
{
|
{
|
||||||
/* Use the entire subcompositor bounds if
|
/* Use the entire subcompositor bounds if
|
||||||
garbaged. */
|
garbaged. */
|
||||||
|
@ -1993,24 +2138,19 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
FillBoxesWithTransparency (subcompositor,
|
FillBoxesWithTransparency (subcompositor,
|
||||||
boxes, nboxes);
|
boxes, nboxes);
|
||||||
|
|
||||||
/* And use PictOpOver as usual. */
|
/* And use over as usual. */
|
||||||
op = PictOpOver;
|
op = OperationOver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
op = PictOpOver;
|
op = OperationOver;
|
||||||
|
|
||||||
first = view;
|
first = view;
|
||||||
|
|
||||||
if (ViewHaveTransform (view))
|
if (ViewHaveTransform (view))
|
||||||
{
|
ViewApplyTransform (view, buffer);
|
||||||
transform = ViewGetTransform (view);
|
|
||||||
|
|
||||||
XRenderSetPictureTransform (compositor.display, picture,
|
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
||||||
&transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsGarbaged (subcompositor))
|
|
||||||
{
|
{
|
||||||
/* First, obtain a new region that is the intersection of
|
/* First, obtain a new region that is the intersection of
|
||||||
the view with the global update region. */
|
the view with the global update region. */
|
||||||
|
@ -2023,20 +2163,17 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
||||||
|
|
||||||
for (i = 0; i < nboxes; ++i)
|
for (i = 0; i < nboxes; ++i)
|
||||||
XRenderComposite (compositor.display, op, picture,
|
RenderComposite (buffer, subcompositor->target, op,
|
||||||
None, subcompositor->target,
|
/* src-x. */
|
||||||
/* src-x. */
|
BoxStartX (boxes[i]) - view->abs_x,
|
||||||
BoxStartX (boxes[i]) - view->abs_x,
|
/* src-y. */
|
||||||
/* src-y. */
|
BoxStartY (boxes[i]) - view->abs_y,
|
||||||
BoxStartY (boxes[i]) - view->abs_y,
|
/* dst-x. */
|
||||||
/* mask-x, mask-y. */
|
BoxStartX (boxes[i]) - min_x + tx,
|
||||||
0, 0,
|
/* dst-y. */
|
||||||
/* dst-x. */
|
BoxStartY (boxes[i]) - min_y + ty,
|
||||||
BoxStartX (boxes[i]) - min_x + tx,
|
/* width, height. */
|
||||||
/* dst-y. */
|
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
||||||
BoxStartY (boxes[i]) - min_y + ty,
|
|
||||||
/* width, height. */
|
|
||||||
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2045,26 +2182,29 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
earlier, since the compositor was garbaged. */
|
earlier, since the compositor was garbaged. */
|
||||||
pixman_region32_clear (&view->damage);
|
pixman_region32_clear (&view->damage);
|
||||||
|
|
||||||
/* If the subcompositor is garbaged, composite the entire view
|
/* If the subcompositor is garbaged, composite the entire
|
||||||
to the right location. */
|
view to the right location. */
|
||||||
XRenderComposite (compositor.display, op, picture,
|
RenderComposite (buffer, subcompositor->target, op,
|
||||||
None, subcompositor->target,
|
/* src-x, src-y. */
|
||||||
/* src-x, src-y. */
|
0, 0,
|
||||||
0, 0,
|
/* dst-x. */
|
||||||
/* mask-x, mask-y. */
|
view->abs_x - min_x + tx,
|
||||||
0, 0,
|
/* dst-y. */
|
||||||
/* dst-x. */
|
view->abs_y - min_y + ty,
|
||||||
view->abs_x - min_x + tx,
|
/* width. */
|
||||||
/* dst-y. */
|
ViewWidth (view),
|
||||||
view->abs_y - min_y + ty,
|
/* height. */
|
||||||
/* width. */
|
ViewHeight (view));
|
||||||
ViewWidth (view),
|
|
||||||
/* height. */
|
|
||||||
ViewHeight (view));
|
|
||||||
|
|
||||||
/* Also adjust the opaque and input regions here. */
|
/* Also adjust the opaque and input regions here. */
|
||||||
|
|
||||||
if (pixman_region32_not_empty (&view->opaque))
|
if (pixman_region32_not_empty (&view->opaque)
|
||||||
|
/* If the subcompositor is garbaged, the opaque region
|
||||||
|
must always be updated. But if we are here because
|
||||||
|
the target is too old, it must only be updated if the
|
||||||
|
opaque region is also dirty. */
|
||||||
|
&& (IsGarbaged (subcompositor)
|
||||||
|
|| IsOpaqueDirty (subcompositor)))
|
||||||
{
|
{
|
||||||
/* Translate the region into the global coordinate
|
/* Translate the region into the global coordinate
|
||||||
space. */
|
space. */
|
||||||
|
@ -2084,7 +2224,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
-list->view->abs_y);
|
-list->view->abs_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pixman_region32_not_empty (&view->input))
|
if (pixman_region32_not_empty (&view->input)
|
||||||
|
/* Ditto for the input region. */
|
||||||
|
&& (IsGarbaged (subcompositor)
|
||||||
|
|| IsInputDirty (subcompositor)))
|
||||||
{
|
{
|
||||||
/* Translate the region into the global coordinate
|
/* Translate the region into the global coordinate
|
||||||
space. */
|
space. */
|
||||||
|
@ -2105,45 +2248,58 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ViewHaveTransform (view))
|
if (ViewHaveTransform (view))
|
||||||
XRenderSetPictureTransform (compositor.display, picture,
|
RenderResetTransform (buffer);
|
||||||
&identity_transform);
|
|
||||||
|
|
||||||
next_1:
|
next_1:
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
while (list != subcompositor->inferiors);
|
while (list != subcompositor->inferiors);
|
||||||
|
|
||||||
|
/* Swap changes to display. */
|
||||||
|
RenderFinishRender (subcompositor->target);
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor))
|
if (IsGarbaged (subcompositor)
|
||||||
|
|| ((age < 0 || age > 3)
|
||||||
|
&& (IsInputDirty (subcompositor)
|
||||||
|
|| IsOpaqueDirty (subcompositor))))
|
||||||
{
|
{
|
||||||
/* The opaque region changed, so run any callbacks. */
|
if (IsGarbaged (subcompositor)
|
||||||
if (subcompositor->opaque_change)
|
|| IsOpaqueDirty (subcompositor))
|
||||||
{
|
{
|
||||||
/* Translate this to appear in the "virtual" coordinate
|
/* The opaque region changed, so run any callbacks. */
|
||||||
space. */
|
if (subcompositor->opaque_change)
|
||||||
pixman_region32_translate (&total_opaque, -min_x, -min_y);
|
{
|
||||||
|
/* Translate this to appear in the "virtual" coordinate
|
||||||
|
space. */
|
||||||
|
pixman_region32_translate (&total_opaque, -min_x, -min_y);
|
||||||
|
|
||||||
subcompositor->opaque_change (subcompositor,
|
subcompositor->opaque_change (subcompositor,
|
||||||
subcompositor->opaque_change_data,
|
subcompositor->opaque_change_data,
|
||||||
&total_opaque);
|
&total_opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_fini (&total_opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini (&total_opaque);
|
if (IsGarbaged (subcompositor)
|
||||||
|
|| IsInputDirty (subcompositor))
|
||||||
/* The input region changed, so run any callbacks. */
|
|
||||||
if (subcompositor->input_change)
|
|
||||||
{
|
{
|
||||||
/* Translate this to appear in the "virtual" coordinate
|
/* The input region changed, so run any callbacks. */
|
||||||
space. */
|
if (subcompositor->input_change)
|
||||||
pixman_region32_translate (&total_input, -min_x, -min_y);
|
{
|
||||||
|
/* Translate this to appear in the "virtual" coordinate
|
||||||
|
space. */
|
||||||
|
pixman_region32_translate (&total_input, -min_x, -min_y);
|
||||||
|
|
||||||
subcompositor->input_change (subcompositor,
|
subcompositor->input_change (subcompositor,
|
||||||
subcompositor->input_change_data,
|
subcompositor->input_change_data,
|
||||||
&total_input);
|
&total_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_fini (&total_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini (&total_input);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini (&temp);
|
pixman_region32_fini (&temp);
|
||||||
|
@ -2163,17 +2319,17 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
View *view;
|
View *view;
|
||||||
int x, y, width, height, nboxes, min_x, min_y, tx, ty;
|
int x, y, width, height, nboxes, min_x, min_y, tx, ty;
|
||||||
pixman_box32_t extents, *boxes;
|
pixman_box32_t extents, *boxes;
|
||||||
int op, i;
|
int i;
|
||||||
|
Operation op;
|
||||||
pixman_region32_t temp;
|
pixman_region32_t temp;
|
||||||
Picture picture;
|
RenderBuffer buffer;
|
||||||
XTransform transform;
|
|
||||||
|
|
||||||
/* Graphics exposures are not yet handled. */
|
/* Graphics exposures are not yet handled. */
|
||||||
if (event->type == GraphicsExpose)
|
if (event->type == GraphicsExpose)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* No target? No update. */
|
/* No target? No update. */
|
||||||
if (subcompositor->target == None)
|
if (!IsTargetAttached (subcompositor))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
x = event->xexpose.x + subcompositor->min_x;
|
x = event->xexpose.x + subcompositor->min_x;
|
||||||
|
@ -2200,6 +2356,10 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
|
|
||||||
list = subcompositor->inferiors;
|
list = subcompositor->inferiors;
|
||||||
|
|
||||||
|
/* Begin rendering. This is unnecessary on XRender, but required on
|
||||||
|
EGL to make the surface current and set the viewport. */
|
||||||
|
RenderStartRender (subcompositor->target);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!list->view)
|
if (!list->view)
|
||||||
|
@ -2217,7 +2377,7 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
/* If the first mapped view contains everything, draw it with
|
/* If the first mapped view contains everything, draw it with
|
||||||
PictOpSrc. */
|
PictOpSrc. */
|
||||||
if (!view && ViewContainsExtents (list->view, &extents))
|
if (!view && ViewContainsExtents (list->view, &extents))
|
||||||
op = PictOpSrc;
|
op = OperationSource;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Otherwise, fill the region with transparency for the
|
/* Otherwise, fill the region with transparency for the
|
||||||
|
@ -2227,7 +2387,7 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
FillBoxesWithTransparency (subcompositor,
|
FillBoxesWithTransparency (subcompositor,
|
||||||
&extents, 1);
|
&extents, 1);
|
||||||
|
|
||||||
op = PictOpOver;
|
op = OperationOver;
|
||||||
}
|
}
|
||||||
|
|
||||||
view = list->view;
|
view = list->view;
|
||||||
|
@ -2240,38 +2400,31 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
ViewHeight (view));
|
ViewHeight (view));
|
||||||
|
|
||||||
/* Composite the contents according to OP. */
|
/* Composite the contents according to OP. */
|
||||||
picture = XLPictureFromBuffer (view->buffer);
|
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||||
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
||||||
|
|
||||||
if (ViewHaveTransform (view))
|
/* Update the attached buffer from any damage. */
|
||||||
{
|
RenderUpdateBufferForDamage (buffer, &list->view->damage);
|
||||||
/* Set up transforms if necessary. */
|
|
||||||
transform = ViewGetTransform (view);
|
|
||||||
|
|
||||||
XRenderSetPictureTransform (compositor.display, picture,
|
if (ViewHaveTransform (view))
|
||||||
&transform);
|
ViewApplyTransform (view, buffer);
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nboxes; ++i)
|
for (i = 0; i < nboxes; ++i)
|
||||||
XRenderComposite (compositor.display, op, picture,
|
RenderComposite (buffer, subcompositor->target, op,
|
||||||
None, subcompositor->target,
|
/* src-x. */
|
||||||
/* src-x. */
|
BoxStartX (boxes[i]) - view->abs_x,
|
||||||
BoxStartX (boxes[i]) - view->abs_x,
|
/* src-y. */
|
||||||
/* src-y. */
|
BoxStartY (boxes[i]) - view->abs_y,
|
||||||
BoxStartY (boxes[i]) - view->abs_y,
|
/* dst-x. */
|
||||||
/* mask-x, mask-y. */
|
BoxStartX (boxes[i]) - min_x + tx,
|
||||||
0, 0,
|
/* dst-y. */
|
||||||
/* dst-x. */
|
BoxStartY (boxes[i]) - min_y + ty,
|
||||||
BoxStartX (boxes[i]) - min_x + tx,
|
/* width, height. */
|
||||||
/* dst-y. */
|
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
||||||
BoxStartY (boxes[i]) - min_y + ty,
|
|
||||||
/* width, height. */
|
|
||||||
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
|
||||||
|
|
||||||
/* Undo transforms that were applied. */
|
/* Undo transforms that were applied. */
|
||||||
if (ViewHaveTransform (view))
|
if (ViewHaveTransform (view))
|
||||||
XRenderSetPictureTransform (compositor.display, picture,
|
RenderResetTransform (buffer);
|
||||||
&identity_transform);
|
|
||||||
|
|
||||||
/* Free the scratch region used to compute the intersection. */
|
/* Free the scratch region used to compute the intersection. */
|
||||||
pixman_region32_fini (&temp);
|
pixman_region32_fini (&temp);
|
||||||
|
@ -2281,6 +2434,9 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
while (list != subcompositor->inferiors);
|
while (list != subcompositor->inferiors);
|
||||||
|
|
||||||
|
/* Swap changes to display. */
|
||||||
|
RenderFinishRender (subcompositor->target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2309,6 +2465,10 @@ SubcompositorFree (Subcompositor *subcompositor)
|
||||||
XLFree (subcompositor->children);
|
XLFree (subcompositor->children);
|
||||||
XLFree (subcompositor->inferiors);
|
XLFree (subcompositor->inferiors);
|
||||||
|
|
||||||
|
/* Finalize the buffers used to store previous damage. */
|
||||||
|
pixman_region32_fini (&subcompositor->prior_damage[0]);
|
||||||
|
pixman_region32_fini (&subcompositor->prior_damage[1]);
|
||||||
|
|
||||||
XLFree (subcompositor);
|
XLFree (subcompositor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2401,9 +2561,7 @@ ViewGetParent (View *view)
|
||||||
void
|
void
|
||||||
SubcompositorInit (void)
|
SubcompositorInit (void)
|
||||||
{
|
{
|
||||||
identity_transform.matrix[0][0] = 1;
|
/* Nothing to do here... */
|
||||||
identity_transform.matrix[1][1] = 1;
|
|
||||||
identity_transform.matrix[2][2] = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
2
xdata.c
2
xdata.c
|
@ -687,7 +687,7 @@ PostReceiveDirect (Time time, Atom selection, Atom target, int fd)
|
||||||
|
|
||||||
static void PostReceiveConversion (Time, Atom, Atom, int);
|
static void PostReceiveConversion (Time, Atom, Atom, int);
|
||||||
|
|
||||||
#define ReceiveBody(selection, primary) \
|
#define ReceiveBody(selection, primary) \
|
||||||
Time time; \
|
Time time; \
|
||||||
TargetMapping *translation; \
|
TargetMapping *translation; \
|
||||||
\
|
\
|
||||||
|
|
|
@ -91,8 +91,8 @@ struct _XdgRole
|
||||||
/* The window backing this role. */
|
/* The window backing this role. */
|
||||||
Window window;
|
Window window;
|
||||||
|
|
||||||
/* The picture backing this role. */
|
/* The render target backing this role. */
|
||||||
Picture picture;
|
RenderTarget target;
|
||||||
|
|
||||||
/* The subcompositor backing this role. */
|
/* The subcompositor backing this role. */
|
||||||
Subcompositor *subcompositor;
|
Subcompositor *subcompositor;
|
||||||
|
@ -775,7 +775,7 @@ ReleaseBacking (XdgRole *role)
|
||||||
XLXdgRoleDetachImplementation (&role->role, role->impl);
|
XLXdgRoleDetachImplementation (&role->role, role->impl);
|
||||||
|
|
||||||
/* Release all allocated resources. */
|
/* Release all allocated resources. */
|
||||||
XRenderFreePicture (compositor.display, role->picture);
|
RenderDestroyRenderTarget (role->target);
|
||||||
XDestroyWindow (compositor.display, role->window);
|
XDestroyWindow (compositor.display, role->window);
|
||||||
|
|
||||||
/* And the association. */
|
/* And the association. */
|
||||||
|
@ -1268,7 +1268,6 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
{
|
{
|
||||||
XdgRole *role;
|
XdgRole *role;
|
||||||
XSetWindowAttributes attrs;
|
XSetWindowAttributes attrs;
|
||||||
XRenderPictureAttributes picture_attrs;
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
Surface *surface;
|
Surface *surface;
|
||||||
|
|
||||||
|
@ -1356,18 +1355,14 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
||||||
0, 0, 20, 20, 0, compositor.n_planes,
|
0, 0, 20, 20, 0, compositor.n_planes,
|
||||||
InputOutput, compositor.visual, flags,
|
InputOutput, compositor.visual, flags,
|
||||||
&attrs);
|
&attrs);
|
||||||
role->picture = XRenderCreatePicture (compositor.display,
|
role->target = RenderTargetFromWindow (role->window);
|
||||||
role->window,
|
|
||||||
/* TODO: get this from the
|
|
||||||
visual instead. */
|
|
||||||
compositor.argb_format,
|
|
||||||
0, &picture_attrs);
|
|
||||||
role->subcompositor = MakeSubcompositor ();
|
role->subcompositor = MakeSubcompositor ();
|
||||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||||
|
|
||||||
XLFrameClockSetFreezeCallback (role->clock, HandleFreeze, role);
|
XLFrameClockSetFreezeCallback (role->clock, HandleFreeze, role);
|
||||||
|
|
||||||
SubcompositorSetTarget (role->subcompositor, role->picture);
|
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||||
SubcompositorSetInputCallback (role->subcompositor,
|
SubcompositorSetInputCallback (role->subcompositor,
|
||||||
InputRegionChanged, role);
|
InputRegionChanged, role);
|
||||||
SubcompositorSetOpaqueCallback (role->subcompositor,
|
SubcompositorSetOpaqueCallback (role->subcompositor,
|
||||||
|
|
5
xerror.c
5
xerror.c
|
@ -92,8 +92,13 @@ ErrorHandler (Display *display, XErrorEvent *event)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (XLHandleErrorForDmabuf (event))
|
if (XLHandleErrorForDmabuf (event))
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (HandleErrorForPictureRenderer (event))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (event->error_code == (xi_first_error + XI_BadDevice))
|
if (event->error_code == (xi_first_error + XI_BadDevice))
|
||||||
/* Various XI requests can result in XI_BadDevice errors if the
|
/* Various XI requests can result in XI_BadDevice errors if the
|
||||||
|
|
Loading…
Add table
Reference in a new issue