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. */
|
||||
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
|
||||
MakeColormap (void)
|
||||
{
|
||||
|
@ -129,8 +100,6 @@ XLMain (int argc, char **argv)
|
|||
compositor.wl_socket = socket;
|
||||
compositor.wl_event_loop
|
||||
= wl_display_get_event_loop (wl_display);
|
||||
compositor.visual = PickVisual (&compositor.n_planes);
|
||||
compositor.colormap = MakeColormap ();
|
||||
|
||||
InitXErrors ();
|
||||
SubcompositorInit ();
|
||||
|
@ -138,6 +107,15 @@ XLMain (int argc, char **argv)
|
|||
|
||||
XLInitTimers ();
|
||||
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 ();
|
||||
XLInitCompositor ();
|
||||
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
|
||||
corresponding _NET_WM_STATE event to arrive. This is only
|
||||
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
|
||||
There is a hard to catch bug where Wayland programs leaving the
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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
|
||||
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 mime4.awk short_types.txt >> $@
|
||||
|
||||
$(OBJS): transfer_atoms.h primary-selection-unstable-v1.h \
|
||||
linux-dmabuf-unstable-v1.h xdg-shell.h
|
||||
$(OBJS): $(GENHEADERS)
|
||||
|
||||
/* 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
|
||||
$(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
|
||||
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
|
||||
complete degree:
|
||||
|
||||
|
@ -58,6 +79,9 @@ This directory is organized as follows:
|
|||
libraries.def - files for libraries that don't provide Imakefiles
|
||||
*.xml - Wayland protocol definition source
|
||||
*.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
|
||||
necessary libwayland-server library, wayland-scanner, pixman, XCB, and
|
||||
|
|
13
buffer.c
13
buffer.c
|
@ -30,7 +30,6 @@ struct _DestroyListener
|
|||
void *data;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
XLRetainBuffer (ExtBuffer *buffer)
|
||||
{
|
||||
|
@ -43,16 +42,10 @@ XLDereferenceBuffer (ExtBuffer *buffer)
|
|||
buffer->funcs.dereference (buffer);
|
||||
}
|
||||
|
||||
Picture
|
||||
XLPictureFromBuffer (ExtBuffer *buffer)
|
||||
RenderBuffer
|
||||
XLRenderBufferFromBuffer (ExtBuffer *buffer)
|
||||
{
|
||||
return buffer->funcs.get_picture (buffer);
|
||||
}
|
||||
|
||||
Pixmap
|
||||
XLPixmapFromBuffer (ExtBuffer *buffer)
|
||||
{
|
||||
return buffer->funcs.get_pixmap (buffer);
|
||||
return buffer->funcs.get_buffer (buffer);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
|
|
298
compositor.h
298
compositor.h
|
@ -94,6 +94,271 @@ typedef struct _PDataSource PDataSource;
|
|||
|
||||
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. */
|
||||
|
||||
typedef struct _PollFd WriteFd;
|
||||
|
@ -189,6 +454,9 @@ extern Time XLGetServerTimeRoundtrip (void);
|
|||
extern RootWindowSelection *XLSelectInputFromRootWindow (unsigned long);
|
||||
extern void XLDeselectInputFromRootWindow (RootWindowSelection *);
|
||||
|
||||
extern void XLRecordBusfault (void *, size_t);
|
||||
extern void XLRemoveBusfault (void *);
|
||||
|
||||
/* Defined in compositor.c. */
|
||||
|
||||
extern void XLInitCompositor (void);
|
||||
|
@ -209,8 +477,7 @@ struct _ExtBufferFuncs
|
|||
{
|
||||
void (*retain) (ExtBuffer *);
|
||||
void (*dereference) (ExtBuffer *);
|
||||
Picture (*get_picture) (ExtBuffer *);
|
||||
Pixmap (*get_pixmap) (ExtBuffer *);
|
||||
RenderBuffer (*get_buffer) (ExtBuffer *);
|
||||
unsigned int (*width) (ExtBuffer *);
|
||||
unsigned int (*height) (ExtBuffer *);
|
||||
void (*release) (ExtBuffer *);
|
||||
|
@ -228,8 +495,7 @@ struct _ExtBuffer
|
|||
|
||||
extern void XLRetainBuffer (ExtBuffer *);
|
||||
extern void XLDereferenceBuffer (ExtBuffer *);
|
||||
extern Picture XLPictureFromBuffer (ExtBuffer *);
|
||||
extern Pixmap XLPixmapFromBuffer (ExtBuffer *);
|
||||
extern RenderBuffer XLRenderBufferFromBuffer (ExtBuffer *);
|
||||
extern unsigned int XLBufferWidth (ExtBuffer *);
|
||||
extern unsigned int XLBufferHeight (ExtBuffer *);
|
||||
extern void XLReleaseBuffer (ExtBuffer *);
|
||||
|
@ -255,7 +521,7 @@ extern void SubcompositorInit (void);
|
|||
extern Subcompositor *MakeSubcompositor (void);
|
||||
extern View *MakeView (void);
|
||||
|
||||
extern void SubcompositorSetTarget (Subcompositor *, Picture);
|
||||
extern void SubcompositorSetTarget (Subcompositor *, RenderTarget *);
|
||||
extern void SubcompositorInsert (Subcompositor *, View *);
|
||||
extern void SubcompositorInsertBefore (Subcompositor *, View *, View *);
|
||||
extern void SubcompositorInsertAfter (Subcompositor *, View *, View *);
|
||||
|
@ -883,8 +1149,6 @@ extern Cursor InitDefaultCursor (void);
|
|||
/* Defined in dmabuf.c. */
|
||||
|
||||
extern void XLInitDmabuf (void);
|
||||
extern Bool XLHandleErrorForDmabuf (XErrorEvent *);
|
||||
extern Bool XLHandleOneXEventForDmabuf (XEvent *);
|
||||
|
||||
/* Defined in select.c. */
|
||||
|
||||
|
@ -985,6 +1249,20 @@ extern Bool XLPDataSourceHasTarget (PDataSource *, const char *);
|
|||
extern int XLPDataSourceTargetCount (PDataSource *);
|
||||
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. */
|
||||
|
||||
#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)))
|
||||
|
||||
#if __GNUC__ >= 7
|
||||
#define Fallthrough __attribute__ ((fallthrough))
|
||||
#else
|
||||
#define Fallthrough ((void) 0)
|
||||
#endif
|
||||
|
||||
/* Taken from intprops.h in gnulib. */
|
||||
|
||||
/* 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/errno.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "compositor.h"
|
||||
|
||||
typedef struct _Busfault Busfault;
|
||||
|
||||
struct _RootWindowSelection
|
||||
{
|
||||
/* The next and last event selection records in this chain. */
|
||||
|
@ -38,9 +42,30 @@ struct _RootWindowSelection
|
|||
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. */
|
||||
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
|
||||
XLListFree (XLList *list, void (*item_func) (void *))
|
||||
{
|
||||
|
@ -473,3 +498,304 @@ XLDeselectInputFromRootWindow (RootWindowSelection *key)
|
|||
XLFree (key);
|
||||
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. */
|
||||
Window window;
|
||||
|
||||
/* The picture associated with this role. */
|
||||
Picture picture;
|
||||
/* The rendering target associated with this role. */
|
||||
RenderTarget target;
|
||||
|
||||
/* The subcompositor associated with this role. */
|
||||
Subcompositor *subcompositor;
|
||||
|
@ -87,7 +87,7 @@ ReleaseBacking (IconSurface *icon)
|
|||
return;
|
||||
|
||||
/* Release all allocated resources. */
|
||||
XRenderFreePicture (compositor.display, icon->picture);
|
||||
RenderDestroyRenderTarget (icon->target);
|
||||
XDestroyWindow (compositor.display, icon->window);
|
||||
|
||||
/* And the association. */
|
||||
|
@ -372,7 +372,6 @@ XLGetIconSurface (Surface *surface)
|
|||
{
|
||||
IconSurface *role;
|
||||
XSetWindowAttributes attrs;
|
||||
XRenderPictureAttributes picture_attrs;
|
||||
unsigned int flags;
|
||||
|
||||
role = XLCalloc (1, sizeof *role);
|
||||
|
@ -410,20 +409,15 @@ XLGetIconSurface (Surface *surface)
|
|||
PropModeReplace,
|
||||
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
||||
|
||||
/* Create a picture associated with the window. */
|
||||
role->picture = XRenderCreatePicture (compositor.display,
|
||||
role->window,
|
||||
/* TODO: get this from the
|
||||
visual instead. */
|
||||
compositor.argb_format,
|
||||
0, &picture_attrs);
|
||||
/* Create a target associated with the window. */
|
||||
role->target = RenderTargetFromWindow (role->window);
|
||||
|
||||
/* Create a subcompositor associated with the window. */
|
||||
role->subcompositor = MakeSubcompositor ();
|
||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||
|
||||
/* Set the subcompositor target and some callbacks. */
|
||||
SubcompositorSetTarget (role->subcompositor, role->picture);
|
||||
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||
SubcompositorSetBoundsCallback (role->subcompositor,
|
||||
NoteBounds, role);
|
||||
|
||||
|
|
|
@ -15,3 +15,12 @@ PIXMANINCLUDES = -I$(INCROOT)/pixman-1
|
|||
system. */
|
||||
|
||||
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))
|
||||
return;
|
||||
|
||||
#if 0
|
||||
if (XLHandleOneXEventForDmabuf (event))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (HandleOneXEventForPictureRenderer (event))
|
||||
return;
|
||||
|
||||
if (XLHandleOneXEventForXData (event))
|
||||
return;
|
||||
|
|
70
seat.c
70
seat.c
|
@ -513,7 +513,7 @@ struct _DeviceInfo
|
|||
#define CursorFromRole(role) ((SeatCursor *) (role))
|
||||
|
||||
/* Subcompositor targets used inside cursor subframes. */
|
||||
static Picture cursor_subframe_picture;
|
||||
static RenderTarget cursor_subframe_target;
|
||||
|
||||
/* Its associated pixmap. */
|
||||
static Pixmap cursor_subframe_pixmap;
|
||||
|
@ -856,22 +856,6 @@ ReleaseSeat (Seat *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
|
||||
ComputeHotspot (SeatCursor *cursor, int min_x, int min_y,
|
||||
int *x, int *y)
|
||||
|
@ -899,19 +883,24 @@ ComputeHotspot (SeatCursor *cursor, int min_x, int min_y,
|
|||
}
|
||||
|
||||
static void
|
||||
ApplyCursor (SeatCursor *cursor, Picture picture,
|
||||
ApplyCursor (SeatCursor *cursor, RenderTarget target,
|
||||
int min_x, int min_y)
|
||||
{
|
||||
Window window;
|
||||
int x, y;
|
||||
Picture picture;
|
||||
|
||||
if (cursor->cursor)
|
||||
XFreeCursor (compositor.display, cursor->cursor);
|
||||
|
||||
ComputeHotspot (cursor, min_x, min_y, &x, &y);
|
||||
|
||||
picture = RenderPictureFromTarget (target);
|
||||
cursor->cursor = XRenderCreateCursor (compositor.display,
|
||||
picture, MAX (0, x),
|
||||
MAX (0, y));
|
||||
RenderFreePictureFromTarget (picture);
|
||||
|
||||
window = CursorWindow (cursor);
|
||||
|
||||
if (!(cursor->seat->flags & IsInert) && window != None)
|
||||
|
@ -923,9 +912,8 @@ ApplyCursor (SeatCursor *cursor, Picture picture,
|
|||
static void
|
||||
UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
||||
{
|
||||
static XRenderColor empty;
|
||||
Picture picture;
|
||||
Pixmap pixmap;
|
||||
RenderTarget target;
|
||||
int min_x, min_y, max_x, max_y, width, height, x, y;
|
||||
Bool need_clear;
|
||||
|
||||
|
@ -963,13 +951,12 @@ UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
|||
pixmap = XCreatePixmap (compositor.display,
|
||||
DefaultRootWindow (compositor.display),
|
||||
width, height, compositor.n_planes);
|
||||
picture = PictureForCursor (pixmap);
|
||||
target = RenderTargetFromPixmap (pixmap);
|
||||
|
||||
/* If the bounds extend beyond the subcompositor, clear the
|
||||
picture. */
|
||||
if (need_clear)
|
||||
XRenderFillRectangle (compositor.display, PictOpClear,
|
||||
picture, &empty, 0, 0, width, height);
|
||||
RenderClearRectangle (target, 0, 0, width, height);
|
||||
|
||||
/* Garbage the subcompositor, since cursor contents are not
|
||||
preserved. */
|
||||
|
@ -979,13 +966,13 @@ UpdateCursorFromSubcompositor (SeatCursor *cursor)
|
|||
SubcompositorSetProjectiveTransform (cursor->subcompositor,
|
||||
MAX (0, -x), MAX (0, -x));
|
||||
|
||||
SubcompositorSetTarget (cursor->subcompositor, picture);
|
||||
SubcompositorSetTarget (cursor->subcompositor, &target);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1081,8 +1068,7 @@ ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
|||
static Bool
|
||||
Subframe (Surface *surface, Role *role)
|
||||
{
|
||||
static XRenderColor empty;
|
||||
Picture picture;
|
||||
RenderTarget target;
|
||||
Pixmap pixmap;
|
||||
int min_x, min_y, max_x, max_y, width, height, x, y;
|
||||
Bool need_clear;
|
||||
|
@ -1129,13 +1115,12 @@ Subframe (Surface *surface, Role *role)
|
|||
pixmap = XCreatePixmap (compositor.display,
|
||||
DefaultRootWindow (compositor.display),
|
||||
width, height, compositor.n_planes);
|
||||
picture = PictureForCursor (pixmap);
|
||||
target = RenderTargetFromPixmap (pixmap);
|
||||
|
||||
/* If the bounds extend beyond the subcompositor, clear the
|
||||
picture. */
|
||||
if (need_clear)
|
||||
XRenderFillRectangle (compositor.display, PictOpClear,
|
||||
picture, &empty, 0, 0, width, height);
|
||||
RenderClearRectangle (target, 0, 0, width, height);
|
||||
|
||||
/* Garbage the subcompositor, since cursor contents are not
|
||||
preserved. */
|
||||
|
@ -1144,10 +1129,14 @@ Subframe (Surface *surface, Role *role)
|
|||
/* Set the right transform if the hotspot is negative. */
|
||||
SubcompositorSetProjectiveTransform (cursor->subcompositor,
|
||||
MAX (0, -x), MAX (0, -x));
|
||||
SubcompositorSetTarget (cursor->subcompositor, picture);
|
||||
|
||||
/* Set the subframe picture to the picture in question. */
|
||||
cursor_subframe_picture = picture;
|
||||
/* Attach the rendering target. */
|
||||
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;
|
||||
|
@ -1161,21 +1150,20 @@ EndSubframe (Surface *surface, Role *role)
|
|||
|
||||
cursor = CursorFromRole (role);
|
||||
|
||||
if (cursor_subframe_picture)
|
||||
if (cursor_subframe_pixmap != None)
|
||||
{
|
||||
/* First, compute the bounds of the subcompositor. */
|
||||
SubcompositorBounds (cursor->subcompositor,
|
||||
&min_x, &min_y, &max_x, &max_y);
|
||||
|
||||
/* 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. */
|
||||
XRenderFreePicture (compositor.display,
|
||||
cursor_subframe_picture);
|
||||
RenderDestroyRenderTarget (cursor_subframe_target);
|
||||
|
||||
/* Finally, clear the target. */
|
||||
SubcompositorSetTarget (cursor->subcompositor, None);
|
||||
SubcompositorSetTarget (cursor->subcompositor, NULL);
|
||||
}
|
||||
else
|
||||
ApplyEmptyCursor (cursor);
|
||||
|
@ -1183,6 +1171,8 @@ EndSubframe (Surface *surface, Role *role)
|
|||
if (cursor_subframe_pixmap)
|
||||
XFreePixmap (compositor.display,
|
||||
cursor_subframe_pixmap);
|
||||
|
||||
cursor_subframe_pixmap = None;
|
||||
}
|
||||
|
||||
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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "compositor.h"
|
||||
|
||||
|
@ -52,24 +49,12 @@ typedef struct _Buffer
|
|||
/* The ExtBuffer associated with this buffer. */
|
||||
ExtBuffer buffer;
|
||||
|
||||
/* The pixmap associated with this buffer. */
|
||||
Pixmap pixmap;
|
||||
|
||||
/* The picture associated with this buffer. */
|
||||
Picture picture;
|
||||
/* The rendering buffer associated with this buffer. */
|
||||
RenderBuffer render_buffer;
|
||||
|
||||
/* The width and height of this buffer. */
|
||||
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. */
|
||||
struct wl_resource *resource;
|
||||
|
||||
|
@ -93,6 +78,14 @@ DereferencePool (Pool *pool)
|
|||
return;
|
||||
|
||||
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);
|
||||
XLFree (pool);
|
||||
}
|
||||
|
@ -115,8 +108,7 @@ DereferenceBuffer (Buffer *buffer)
|
|||
if (--buffer->refcount)
|
||||
return;
|
||||
|
||||
XRenderFreePicture (compositor.display, buffer->picture);
|
||||
XFreePixmap (compositor.display, buffer->pixmap);
|
||||
RenderFreeShmBuffer (buffer->render_buffer);
|
||||
DereferencePool (buffer->pool);
|
||||
|
||||
ExtBufferDestroy (&buffer->buffer);
|
||||
|
@ -142,16 +134,10 @@ DereferenceBufferFunc (ExtBuffer *buffer)
|
|||
DereferenceBuffer ((Buffer *) buffer);
|
||||
}
|
||||
|
||||
static Picture
|
||||
GetPictureFunc (ExtBuffer *buffer)
|
||||
static RenderBuffer
|
||||
GetBufferFunc (ExtBuffer *buffer)
|
||||
{
|
||||
return ((Buffer *) buffer)->picture;
|
||||
}
|
||||
|
||||
static Pixmap
|
||||
GetPixmapFunc (ExtBuffer *buffer)
|
||||
{
|
||||
return ((Buffer *) buffer)->pixmap;
|
||||
return ((Buffer *) buffer)->render_buffer;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
|
@ -175,20 +161,7 @@ DestroyBuffer (struct wl_client *client, struct wl_resource *resource)
|
|||
static void
|
||||
PrintBuffer (Buffer *buffer)
|
||||
{
|
||||
int x, y;
|
||||
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");
|
||||
}
|
||||
/* Not implemented. */
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -197,37 +170,6 @@ PrintBufferFunc (ExtBuffer *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
|
||||
HandleBufferResourceDestroy (struct wl_resource *resource)
|
||||
|
@ -245,22 +187,35 @@ static const struct wl_buffer_interface wl_shm_buffer_impl =
|
|||
.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
|
||||
CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
||||
uint32_t id, int32_t offset, int32_t width, int32_t height,
|
||||
int32_t stride, uint32_t format)
|
||||
{
|
||||
XRenderPictureAttributes picture_attrs;
|
||||
Pool *pool;
|
||||
Buffer *buffer;
|
||||
xcb_shm_seg_t seg;
|
||||
Pixmap pixmap;
|
||||
Picture picture;
|
||||
int fd, depth;
|
||||
RenderBuffer render_buffer;
|
||||
SharedMemoryAttributes attrs;
|
||||
Bool failure;
|
||||
|
||||
depth = DepthForFormat (format);
|
||||
|
||||
if (!depth)
|
||||
if (!IsFormatSupported (format))
|
||||
{
|
||||
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FORMAT,
|
||||
"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);
|
||||
|
||||
if (pool->size < offset || stride != width * 4
|
||||
|| offset + stride * height > pool->size
|
||||
|| offset < 0)
|
||||
if (!RenderValidateShmParams (format, width, height,
|
||||
offset, stride, pool->size))
|
||||
{
|
||||
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_STRIDE,
|
||||
"invalid offset or stride, or pool too small");
|
||||
|
@ -314,46 +268,43 @@ CreateBuffer (struct wl_client *client, struct wl_resource *resource,
|
|||
return;
|
||||
}
|
||||
|
||||
/* XCB closes fds after sending them. */
|
||||
fd = fcntl (pool->fd, F_DUPFD_CLOEXEC, 0);
|
||||
attrs.format = format;
|
||||
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);
|
||||
XLFree (buffer);
|
||||
wl_resource_post_error (resource, WL_SHM_ERROR_INVALID_FD,
|
||||
"fcntl: %s", strerror (errno));
|
||||
"unknown error creating buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
seg = xcb_generate_id (compositor.conn);
|
||||
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->render_buffer = render_buffer;
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->stride = stride;
|
||||
buffer->offset = offset;
|
||||
buffer->format = format;
|
||||
buffer->pool = pool;
|
||||
buffer->refcount = 1;
|
||||
|
||||
/* Initialize function pointers. */
|
||||
buffer->buffer.funcs.retain = RetainBufferFunc;
|
||||
buffer->buffer.funcs.dereference = DereferenceBufferFunc;
|
||||
buffer->buffer.funcs.get_picture = GetPictureFunc;
|
||||
buffer->buffer.funcs.get_pixmap = GetPixmapFunc;
|
||||
buffer->buffer.funcs.get_buffer = GetBufferFunc;
|
||||
buffer->buffer.funcs.width = WidthFunc;
|
||||
buffer->buffer.funcs.height = HeightFunc;
|
||||
buffer->buffer.funcs.release = ReleaseBufferFunc;
|
||||
|
@ -390,6 +341,19 @@ ResizePool (struct wl_client *client, struct wl_resource *resource,
|
|||
void *data;
|
||||
|
||||
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);
|
||||
|
||||
if (data == MAP_FAILED)
|
||||
|
@ -399,8 +363,17 @@ ResizePool (struct wl_client *client, struct wl_resource *resource,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Now cancel the existing bus fault handler, should it have been
|
||||
installed. */
|
||||
if (pool->size)
|
||||
XLRemoveBusfault (pool->data);
|
||||
|
||||
pool->size = size;
|
||||
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 =
|
||||
|
@ -417,9 +390,8 @@ HandleResourceDestroy (struct wl_resource *resource)
|
|||
}
|
||||
|
||||
static void
|
||||
CreatePool (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id, int fd, int size)
|
||||
CreatePool (struct wl_client *client, struct wl_resource *resource,
|
||||
uint32_t id, int32_t fd, int32_t size)
|
||||
{
|
||||
Pool *pool;
|
||||
|
||||
|
@ -459,6 +431,13 @@ CreatePool (struct wl_client *client,
|
|||
pool, HandlePoolResourceDestroy);
|
||||
|
||||
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->refcount = 1;
|
||||
|
||||
|
@ -473,10 +452,13 @@ static const struct wl_shm_interface wl_shm_impl =
|
|||
static void
|
||||
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);
|
||||
wl_shm_send_format (resource, WL_SHM_FORMAT_ARGB8888);
|
||||
formats = RenderGetShmFormats (&nformats);
|
||||
|
||||
for (i = 0; i < nformats; ++i)
|
||||
wl_shm_send_format (resource, formats[i].format);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -544,40 +526,6 @@ InitRender (void)
|
|||
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 ();
|
||||
|
||||
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
|
||||
subcompositing optimisations should be skipped. */
|
||||
SubcompositorIsGarbaged = 1,
|
||||
SubcompositorIsGarbaged = 1,
|
||||
/* This means that the opaque region of one of the views
|
||||
changed. */
|
||||
SubcompositorIsOpaqueDirty = (1 << 2),
|
||||
SubcompositorIsOpaqueDirty = (1 << 2),
|
||||
/* This means that the input region of one of the views
|
||||
changed. */
|
||||
SubcompositorIsInputDirty = (1 << 3),
|
||||
SubcompositorIsInputDirty = (1 << 3),
|
||||
/* This means that there is at least one unmapped view in this
|
||||
subcompositor. */
|
||||
SubcompositorIsPartiallyMapped = (1 << 4),
|
||||
SubcompositorIsPartiallyMapped = (1 << 4),
|
||||
/* This means that the subcompositor is frozen and updates should
|
||||
do nothing. */
|
||||
SubcompositorIsFrozen = (1 << 5),
|
||||
SubcompositorIsFrozen = (1 << 5),
|
||||
/* This means that the subcompositor has a target attached. */
|
||||
SubcompositorIsTargetAttached = (1 << 6),
|
||||
};
|
||||
|
||||
#define IsGarbaged(subcompositor) \
|
||||
|
@ -179,6 +181,11 @@ enum
|
|||
#define IsFrozen(subcompositor) \
|
||||
((subcompositor)->state & SubcompositorIsFrozen)
|
||||
|
||||
#define SetTargetAttached(subcompositor) \
|
||||
((subcompositor)->state |= SubcompositorIsTargetAttached)
|
||||
#define IsTargetAttached(subcompositor) \
|
||||
((subcompositor)->state & SubcompositorIsTargetAttached)
|
||||
|
||||
#ifndef TEST
|
||||
|
||||
enum
|
||||
|
@ -218,11 +225,6 @@ struct _View
|
|||
into a compositor. */
|
||||
Subcompositor *subcompositor;
|
||||
|
||||
#ifndef TEST
|
||||
/* Picture this subcompositor draws to. */
|
||||
Picture picture;
|
||||
#endif
|
||||
|
||||
/* Pointer to the parent view. NULL if the parent is the
|
||||
subcompositor itself. */
|
||||
View *parent;
|
||||
|
@ -289,8 +291,8 @@ struct _Subcompositor
|
|||
List *children, *last_children;
|
||||
|
||||
#ifndef TEST
|
||||
/* The picture that is rendered to. */
|
||||
Picture target;
|
||||
/* Target this subcompositor draws to. */
|
||||
RenderTarget target;
|
||||
|
||||
/* Function called when the opaque region changes. */
|
||||
void (*opaque_change) (Subcompositor *, void *,
|
||||
|
@ -316,6 +318,14 @@ struct _Subcompositor
|
|||
|
||||
/* An additional offset to apply when drawing to the target. */
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -330,10 +340,6 @@ enum
|
|||
DoAll = 0xf,
|
||||
};
|
||||
|
||||
/* The identity transform. */
|
||||
|
||||
static XTransform identity_transform;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -411,6 +417,10 @@ MakeSubcompositor (void)
|
|||
subcompositor->last = subcompositor->inferiors;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -562,9 +572,16 @@ SubcompositorUpdateBoundsForInsert (Subcompositor *subcompositor,
|
|||
#ifndef TEST
|
||||
|
||||
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
|
||||
over. */
|
||||
|
@ -1171,6 +1188,19 @@ main (int argc, char **argv)
|
|||
the target drawable. Afterwards, the damage region of each
|
||||
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
|
||||
of a view changes. In the interest of keeping thing simple, every
|
||||
inferior is composited onto the target drawable whenever a view
|
||||
|
@ -1560,21 +1590,10 @@ GetTxTy (int scale)
|
|||
return 1.0 / (-scale + 1);
|
||||
}
|
||||
|
||||
static XTransform
|
||||
ViewGetTransform (View *view)
|
||||
static void
|
||||
ViewApplyTransform (View *view, RenderBuffer buffer)
|
||||
{
|
||||
XTransform transform;
|
||||
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;
|
||||
RenderApplyTransform (buffer, GetTxTy (view->scale));
|
||||
}
|
||||
|
||||
/* TODO: the callers of this can be optimized by setting the picture
|
||||
|
@ -1625,31 +1644,9 @@ static void
|
|||
FillBoxesWithTransparency (Subcompositor *subcompositor,
|
||||
pixman_box32_t *boxes, int nboxes)
|
||||
{
|
||||
XRectangle *rects;
|
||||
static XRenderColor color;
|
||||
int i;
|
||||
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);
|
||||
RenderFillBoxesWithTransparency (subcompositor->target, boxes,
|
||||
nboxes, subcompositor->min_x,
|
||||
subcompositor->min_y);
|
||||
}
|
||||
|
||||
static Bool
|
||||
|
@ -1684,6 +1681,52 @@ SubcompositorIsEmpty (Subcompositor *subcompositor)
|
|||
&& 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
|
||||
SubcompositorUpdate (Subcompositor *subcompositor)
|
||||
{
|
||||
|
@ -1692,13 +1735,14 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
View *start, *original_start, *view, *first;
|
||||
List *list;
|
||||
pixman_box32_t *boxes, *extents, temp_boxes;
|
||||
int nboxes, i, op, tx, ty;
|
||||
Picture picture;
|
||||
XTransform transform;
|
||||
int nboxes, i, tx, ty;
|
||||
Operation op;
|
||||
RenderBuffer buffer;
|
||||
int min_x, min_y;
|
||||
int age;
|
||||
|
||||
/* Just return if no target was specified. */
|
||||
if (subcompositor->target == None)
|
||||
if (!IsTargetAttached (subcompositor))
|
||||
return;
|
||||
|
||||
/* Likewise if the subcompositor is "frozen". */
|
||||
|
@ -1717,6 +1761,31 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
|
||||
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
|
||||
there is actually a partially mapped view. */
|
||||
|
@ -1727,7 +1796,17 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
min_x, min_y, subcompositor->max_x,
|
||||
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;
|
||||
original_start = NULL;
|
||||
|
@ -1793,8 +1872,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
&update_region, &temp);
|
||||
|
||||
/* This view will obscure all preceding damaged areas,
|
||||
so make start here. */
|
||||
if (!pixman_region32_not_empty (&update_region))
|
||||
so make start here. This optimization is disabled if
|
||||
the target contents are too old, as prior damage
|
||||
could reveal contents below. */
|
||||
if (!pixman_region32_not_empty (&update_region) && !age)
|
||||
{
|
||||
start = list->view;
|
||||
|
||||
|
@ -1834,6 +1915,14 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
|
||||
if (pixman_region32_not_empty (&list->view->damage))
|
||||
{
|
||||
/* Update the attached buffer from the damage. This is
|
||||
only required on some backends, where we have to
|
||||
upload data from a shared memory buffer to the
|
||||
graphics hardware. */
|
||||
|
||||
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||
RenderUpdateBufferForDamage (buffer, &list->view->damage);
|
||||
|
||||
/* Translate the region into the subcompositor
|
||||
coordinate space. */
|
||||
pixman_region32_translate (&list->view->damage,
|
||||
|
@ -1906,13 +1995,48 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
/* To save from iterating over all the views twice, perform the
|
||||
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. */
|
||||
|
@ -1925,6 +2049,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
list = start->link;
|
||||
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
|
||||
{
|
||||
view = list->view;
|
||||
|
@ -1947,7 +2075,24 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
if (!view->buffer)
|
||||
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)
|
||||
{
|
||||
|
@ -1955,7 +2100,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
with PictOpSrc so that transparency is applied correctly,
|
||||
if it contains the entire update region. */
|
||||
|
||||
if (IsGarbaged (subcompositor))
|
||||
if (IsGarbaged (subcompositor) || age < 0 || age > 3)
|
||||
{
|
||||
extents = &temp_boxes;
|
||||
|
||||
|
@ -1971,14 +2116,14 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
|
||||
if (ViewContainsExtents (view, extents))
|
||||
/* The update region is contained by the entire view, so
|
||||
use PictOpSrc. */
|
||||
op = PictOpSrc;
|
||||
use source. */
|
||||
op = OperationSource;
|
||||
else
|
||||
{
|
||||
/* Otherwise, fill the whole update region with
|
||||
transparency. */
|
||||
|
||||
if (IsGarbaged (subcompositor))
|
||||
if (IsGarbaged (subcompositor) || age < 0 || age > 3)
|
||||
{
|
||||
/* Use the entire subcompositor bounds if
|
||||
garbaged. */
|
||||
|
@ -1993,24 +2138,19 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
FillBoxesWithTransparency (subcompositor,
|
||||
boxes, nboxes);
|
||||
|
||||
/* And use PictOpOver as usual. */
|
||||
op = PictOpOver;
|
||||
/* And use over as usual. */
|
||||
op = OperationOver;
|
||||
}
|
||||
}
|
||||
else
|
||||
op = PictOpOver;
|
||||
op = OperationOver;
|
||||
|
||||
first = view;
|
||||
|
||||
if (ViewHaveTransform (view))
|
||||
{
|
||||
transform = ViewGetTransform (view);
|
||||
ViewApplyTransform (view, buffer);
|
||||
|
||||
XRenderSetPictureTransform (compositor.display, picture,
|
||||
&transform);
|
||||
}
|
||||
|
||||
if (!IsGarbaged (subcompositor))
|
||||
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
||||
{
|
||||
/* First, obtain a new region that is the intersection of
|
||||
the view with the global update region. */
|
||||
|
@ -2023,20 +2163,17 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
||||
|
||||
for (i = 0; i < nboxes; ++i)
|
||||
XRenderComposite (compositor.display, op, picture,
|
||||
None, subcompositor->target,
|
||||
/* src-x. */
|
||||
BoxStartX (boxes[i]) - view->abs_x,
|
||||
/* src-y. */
|
||||
BoxStartY (boxes[i]) - view->abs_y,
|
||||
/* mask-x, mask-y. */
|
||||
0, 0,
|
||||
/* dst-x. */
|
||||
BoxStartX (boxes[i]) - min_x + tx,
|
||||
/* dst-y. */
|
||||
BoxStartY (boxes[i]) - min_y + ty,
|
||||
/* width, height. */
|
||||
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
||||
RenderComposite (buffer, subcompositor->target, op,
|
||||
/* src-x. */
|
||||
BoxStartX (boxes[i]) - view->abs_x,
|
||||
/* src-y. */
|
||||
BoxStartY (boxes[i]) - view->abs_y,
|
||||
/* dst-x. */
|
||||
BoxStartX (boxes[i]) - min_x + tx,
|
||||
/* dst-y. */
|
||||
BoxStartY (boxes[i]) - min_y + ty,
|
||||
/* width, height. */
|
||||
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2045,26 +2182,29 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
earlier, since the compositor was garbaged. */
|
||||
pixman_region32_clear (&view->damage);
|
||||
|
||||
/* If the subcompositor is garbaged, composite the entire view
|
||||
to the right location. */
|
||||
XRenderComposite (compositor.display, op, picture,
|
||||
None, subcompositor->target,
|
||||
/* src-x, src-y. */
|
||||
0, 0,
|
||||
/* mask-x, mask-y. */
|
||||
0, 0,
|
||||
/* dst-x. */
|
||||
view->abs_x - min_x + tx,
|
||||
/* dst-y. */
|
||||
view->abs_y - min_y + ty,
|
||||
/* width. */
|
||||
ViewWidth (view),
|
||||
/* height. */
|
||||
ViewHeight (view));
|
||||
/* If the subcompositor is garbaged, composite the entire
|
||||
view to the right location. */
|
||||
RenderComposite (buffer, subcompositor->target, op,
|
||||
/* src-x, src-y. */
|
||||
0, 0,
|
||||
/* dst-x. */
|
||||
view->abs_x - min_x + tx,
|
||||
/* dst-y. */
|
||||
view->abs_y - min_y + ty,
|
||||
/* width. */
|
||||
ViewWidth (view),
|
||||
/* height. */
|
||||
ViewHeight (view));
|
||||
|
||||
/* 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
|
||||
space. */
|
||||
|
@ -2084,7 +2224,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
-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
|
||||
space. */
|
||||
|
@ -2105,45 +2248,58 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
}
|
||||
|
||||
if (ViewHaveTransform (view))
|
||||
XRenderSetPictureTransform (compositor.display, picture,
|
||||
&identity_transform);
|
||||
RenderResetTransform (buffer);
|
||||
|
||||
next_1:
|
||||
list = list->next;
|
||||
}
|
||||
while (list != subcompositor->inferiors);
|
||||
|
||||
/* Swap changes to display. */
|
||||
RenderFinishRender (subcompositor->target);
|
||||
|
||||
complete:
|
||||
|
||||
if (IsGarbaged (subcompositor))
|
||||
if (IsGarbaged (subcompositor)
|
||||
|| ((age < 0 || age > 3)
|
||||
&& (IsInputDirty (subcompositor)
|
||||
|| IsOpaqueDirty (subcompositor))))
|
||||
{
|
||||
/* The opaque region changed, so run any callbacks. */
|
||||
if (subcompositor->opaque_change)
|
||||
if (IsGarbaged (subcompositor)
|
||||
|| IsOpaqueDirty (subcompositor))
|
||||
{
|
||||
/* Translate this to appear in the "virtual" coordinate
|
||||
space. */
|
||||
pixman_region32_translate (&total_opaque, -min_x, -min_y);
|
||||
/* The opaque region changed, so run any callbacks. */
|
||||
if (subcompositor->opaque_change)
|
||||
{
|
||||
/* 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_data,
|
||||
&total_opaque);
|
||||
subcompositor->opaque_change (subcompositor,
|
||||
subcompositor->opaque_change_data,
|
||||
&total_opaque);
|
||||
}
|
||||
|
||||
pixman_region32_fini (&total_opaque);
|
||||
}
|
||||
|
||||
pixman_region32_fini (&total_opaque);
|
||||
|
||||
/* The input region changed, so run any callbacks. */
|
||||
if (subcompositor->input_change)
|
||||
if (IsGarbaged (subcompositor)
|
||||
|| IsInputDirty (subcompositor))
|
||||
{
|
||||
/* Translate this to appear in the "virtual" coordinate
|
||||
space. */
|
||||
pixman_region32_translate (&total_input, -min_x, -min_y);
|
||||
/* The input region changed, so run any callbacks. */
|
||||
if (subcompositor->input_change)
|
||||
{
|
||||
/* 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_data,
|
||||
&total_input);
|
||||
subcompositor->input_change (subcompositor,
|
||||
subcompositor->input_change_data,
|
||||
&total_input);
|
||||
}
|
||||
|
||||
pixman_region32_fini (&total_input);
|
||||
}
|
||||
|
||||
pixman_region32_fini (&total_input);
|
||||
}
|
||||
|
||||
pixman_region32_fini (&temp);
|
||||
|
@ -2163,17 +2319,17 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
|||
View *view;
|
||||
int x, y, width, height, nboxes, min_x, min_y, tx, ty;
|
||||
pixman_box32_t extents, *boxes;
|
||||
int op, i;
|
||||
int i;
|
||||
Operation op;
|
||||
pixman_region32_t temp;
|
||||
Picture picture;
|
||||
XTransform transform;
|
||||
RenderBuffer buffer;
|
||||
|
||||
/* Graphics exposures are not yet handled. */
|
||||
if (event->type == GraphicsExpose)
|
||||
return;
|
||||
|
||||
/* No target? No update. */
|
||||
if (subcompositor->target == None)
|
||||
if (!IsTargetAttached (subcompositor))
|
||||
return;
|
||||
|
||||
x = event->xexpose.x + subcompositor->min_x;
|
||||
|
@ -2200,6 +2356,10 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
|||
|
||||
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
|
||||
{
|
||||
if (!list->view)
|
||||
|
@ -2217,7 +2377,7 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
|||
/* If the first mapped view contains everything, draw it with
|
||||
PictOpSrc. */
|
||||
if (!view && ViewContainsExtents (list->view, &extents))
|
||||
op = PictOpSrc;
|
||||
op = OperationSource;
|
||||
else
|
||||
{
|
||||
/* Otherwise, fill the region with transparency for the
|
||||
|
@ -2227,7 +2387,7 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
|||
FillBoxesWithTransparency (subcompositor,
|
||||
&extents, 1);
|
||||
|
||||
op = PictOpOver;
|
||||
op = OperationOver;
|
||||
}
|
||||
|
||||
view = list->view;
|
||||
|
@ -2240,38 +2400,31 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
|||
ViewHeight (view));
|
||||
|
||||
/* Composite the contents according to OP. */
|
||||
picture = XLPictureFromBuffer (view->buffer);
|
||||
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
||||
|
||||
if (ViewHaveTransform (view))
|
||||
{
|
||||
/* Set up transforms if necessary. */
|
||||
transform = ViewGetTransform (view);
|
||||
/* Update the attached buffer from any damage. */
|
||||
RenderUpdateBufferForDamage (buffer, &list->view->damage);
|
||||
|
||||
XRenderSetPictureTransform (compositor.display, picture,
|
||||
&transform);
|
||||
}
|
||||
if (ViewHaveTransform (view))
|
||||
ViewApplyTransform (view, buffer);
|
||||
|
||||
for (i = 0; i < nboxes; ++i)
|
||||
XRenderComposite (compositor.display, op, picture,
|
||||
None, subcompositor->target,
|
||||
/* src-x. */
|
||||
BoxStartX (boxes[i]) - view->abs_x,
|
||||
/* src-y. */
|
||||
BoxStartY (boxes[i]) - view->abs_y,
|
||||
/* mask-x, mask-y. */
|
||||
0, 0,
|
||||
/* dst-x. */
|
||||
BoxStartX (boxes[i]) - min_x + tx,
|
||||
/* dst-y. */
|
||||
BoxStartY (boxes[i]) - min_y + ty,
|
||||
/* width, height. */
|
||||
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
||||
RenderComposite (buffer, subcompositor->target, op,
|
||||
/* src-x. */
|
||||
BoxStartX (boxes[i]) - view->abs_x,
|
||||
/* src-y. */
|
||||
BoxStartY (boxes[i]) - view->abs_y,
|
||||
/* dst-x. */
|
||||
BoxStartX (boxes[i]) - min_x + tx,
|
||||
/* dst-y. */
|
||||
BoxStartY (boxes[i]) - min_y + ty,
|
||||
/* width, height. */
|
||||
BoxWidth (boxes[i]), BoxHeight (boxes[i]));
|
||||
|
||||
/* Undo transforms that were applied. */
|
||||
if (ViewHaveTransform (view))
|
||||
XRenderSetPictureTransform (compositor.display, picture,
|
||||
&identity_transform);
|
||||
RenderResetTransform (buffer);
|
||||
|
||||
/* Free the scratch region used to compute the intersection. */
|
||||
pixman_region32_fini (&temp);
|
||||
|
@ -2281,6 +2434,9 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
|||
list = list->next;
|
||||
}
|
||||
while (list != subcompositor->inferiors);
|
||||
|
||||
/* Swap changes to display. */
|
||||
RenderFinishRender (subcompositor->target);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2309,6 +2465,10 @@ SubcompositorFree (Subcompositor *subcompositor)
|
|||
XLFree (subcompositor->children);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2401,9 +2561,7 @@ ViewGetParent (View *view)
|
|||
void
|
||||
SubcompositorInit (void)
|
||||
{
|
||||
identity_transform.matrix[0][0] = 1;
|
||||
identity_transform.matrix[1][1] = 1;
|
||||
identity_transform.matrix[2][2] = 1;
|
||||
/* Nothing to do here... */
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#define ReceiveBody(selection, primary) \
|
||||
#define ReceiveBody(selection, primary) \
|
||||
Time time; \
|
||||
TargetMapping *translation; \
|
||||
\
|
||||
|
|
|
@ -91,8 +91,8 @@ struct _XdgRole
|
|||
/* The window backing this role. */
|
||||
Window window;
|
||||
|
||||
/* The picture backing this role. */
|
||||
Picture picture;
|
||||
/* The render target backing this role. */
|
||||
RenderTarget target;
|
||||
|
||||
/* The subcompositor backing this role. */
|
||||
Subcompositor *subcompositor;
|
||||
|
@ -775,7 +775,7 @@ ReleaseBacking (XdgRole *role)
|
|||
XLXdgRoleDetachImplementation (&role->role, role->impl);
|
||||
|
||||
/* Release all allocated resources. */
|
||||
XRenderFreePicture (compositor.display, role->picture);
|
||||
RenderDestroyRenderTarget (role->target);
|
||||
XDestroyWindow (compositor.display, role->window);
|
||||
|
||||
/* And the association. */
|
||||
|
@ -1268,7 +1268,6 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
|||
{
|
||||
XdgRole *role;
|
||||
XSetWindowAttributes attrs;
|
||||
XRenderPictureAttributes picture_attrs;
|
||||
unsigned int flags;
|
||||
Surface *surface;
|
||||
|
||||
|
@ -1356,18 +1355,14 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
|
|||
0, 0, 20, 20, 0, compositor.n_planes,
|
||||
InputOutput, compositor.visual, flags,
|
||||
&attrs);
|
||||
role->picture = XRenderCreatePicture (compositor.display,
|
||||
role->window,
|
||||
/* TODO: get this from the
|
||||
visual instead. */
|
||||
compositor.argb_format,
|
||||
0, &picture_attrs);
|
||||
role->target = RenderTargetFromWindow (role->window);
|
||||
|
||||
role->subcompositor = MakeSubcompositor ();
|
||||
role->clock = XLMakeFrameClockForWindow (role->window);
|
||||
|
||||
XLFrameClockSetFreezeCallback (role->clock, HandleFreeze, role);
|
||||
|
||||
SubcompositorSetTarget (role->subcompositor, role->picture);
|
||||
SubcompositorSetTarget (role->subcompositor, &role->target);
|
||||
SubcompositorSetInputCallback (role->subcompositor,
|
||||
InputRegionChanged, role);
|
||||
SubcompositorSetOpaqueCallback (role->subcompositor,
|
||||
|
|
5
xerror.c
5
xerror.c
|
@ -92,8 +92,13 @@ ErrorHandler (Display *display, XErrorEvent *event)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (XLHandleErrorForDmabuf (event))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (HandleErrorForPictureRenderer (event))
|
||||
return 0;
|
||||
|
||||
if (event->error_code == (xi_first_error + XI_BadDevice))
|
||||
/* Various XI requests can result in XI_BadDevice errors if the
|
||||
|
|
Loading…
Add table
Reference in a new issue