mirror of
https://github.com/X11Libre/xf86-video-vmware.git
synced 2026-03-24 01:24:37 +00:00
Use server's new lifecycle API. That's an important step in order to decouple ourselves from the old, fragile proc wrapping. Without it, the driver might not work on newer Xservers anymore. For old Xservers adding a fallback. Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
778 lines
21 KiB
C
778 lines
21 KiB
C
/*
|
|
* Copyright © 2001 Keith Packard
|
|
*
|
|
* Partly based on code that is Copyright © The XFree86 Project Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Keith Packard makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/** @file
|
|
* This file covers the initialization and teardown of SAA, and has various
|
|
* functions not responsible for performing rendering, pixmap migration, or
|
|
* memory management.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "saa_priv.h"
|
|
#include <X11/fonts/fontstruct.h>
|
|
#include "regionstr.h"
|
|
#include "saa.h"
|
|
#include "saa_priv.h"
|
|
|
|
DevPrivateKeyRec saa_screen_index;
|
|
DevPrivateKeyRec saa_pixmap_index;
|
|
DevPrivateKeyRec saa_gc_index;
|
|
|
|
/**
|
|
* saa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
|
|
*
|
|
* @param pDrawable the drawable being requested.
|
|
*
|
|
* This function returns the backing pixmap for a drawable, whether it is a
|
|
* redirected window, unredirected window, or already a pixmap. Note that
|
|
* coordinate translation is needed when drawing to the backing pixmap of a
|
|
* redirected window, and the translation coordinates are provided by calling
|
|
* saa_get_drawable_pixmap() on the drawable.
|
|
*/
|
|
PixmapPtr
|
|
saa_get_drawable_pixmap(DrawablePtr pDrawable)
|
|
{
|
|
if (pDrawable->type == DRAWABLE_WINDOW)
|
|
return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable);
|
|
else
|
|
return (PixmapPtr) pDrawable;
|
|
}
|
|
|
|
/**
|
|
* Sets the offsets to add to coordinates to make them address the same bits in
|
|
* the backing drawable. These coordinates are nonzero only for redirected
|
|
* windows.
|
|
*/
|
|
void
|
|
saa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
|
|
int *xp, int *yp)
|
|
{
|
|
#ifdef COMPOSITE
|
|
if (pDrawable->type == DRAWABLE_WINDOW) {
|
|
*xp = -pPixmap->screen_x;
|
|
*yp = -pPixmap->screen_y;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
*xp = 0;
|
|
*yp = 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the pixmap which backs a drawable, and the offsets to add to
|
|
* coordinates to make them address the same bits in the backing drawable.
|
|
*/
|
|
PixmapPtr
|
|
saa_get_pixmap(DrawablePtr drawable, int *xp, int *yp)
|
|
{
|
|
PixmapPtr pixmap = saa_get_drawable_pixmap(drawable);
|
|
|
|
saa_get_drawable_deltas(drawable, pixmap, xp, yp);
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
static Bool
|
|
saa_download_from_hw(PixmapPtr pix, RegionPtr readback)
|
|
{
|
|
struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
|
|
struct saa_driver *driver = sscreen->driver;
|
|
struct saa_pixmap *spix = saa_pixmap(pix);
|
|
void *addr;
|
|
Bool ret;
|
|
|
|
if (spix->mapped_access)
|
|
driver->release_from_cpu(driver, pix, spix->mapped_access);
|
|
|
|
ret = driver->download_from_hw(driver, pix, readback);
|
|
|
|
if (spix->mapped_access) {
|
|
addr = driver->sync_for_cpu(driver, pix, spix->mapped_access);
|
|
if (addr != NULL)
|
|
spix->addr = addr;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Bool
|
|
saa_prepare_access_pixmap(PixmapPtr pix, saa_access_t access,
|
|
RegionPtr read_reg)
|
|
{
|
|
ScreenPtr pScreen = pix->drawable.pScreen;
|
|
struct saa_screen_priv *sscreen = saa_screen(pScreen);
|
|
struct saa_driver *driver = sscreen->driver;
|
|
struct saa_pixmap *spix = saa_pixmap(pix);
|
|
saa_access_t map_access = 0;
|
|
Bool ret = TRUE;
|
|
|
|
if (read_reg && REGION_NOTEMPTY(pScreen, read_reg))
|
|
ret = saa_download_from_hw(pix, read_reg);
|
|
|
|
if (!ret) {
|
|
LogMessage(X_ERROR, "Prepare access pixmap failed.\n");
|
|
return ret;
|
|
}
|
|
|
|
if ((access & SAA_ACCESS_R) != 0 && spix->read_access++ == 0)
|
|
map_access = SAA_ACCESS_R;
|
|
if ((access & SAA_ACCESS_W) != 0 && spix->write_access++ == 0)
|
|
map_access |= SAA_ACCESS_W;
|
|
|
|
if (map_access) {
|
|
if (spix->auth_loc != saa_loc_override) {
|
|
(void)driver->sync_for_cpu(driver, pix, map_access);
|
|
spix->addr = driver->map(driver, pix, map_access);
|
|
} else
|
|
spix->addr = spix->override;
|
|
spix->mapped_access |= map_access;
|
|
}
|
|
|
|
pix->devPrivate.ptr = spix->addr;
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
saa_finish_access_pixmap(PixmapPtr pix, saa_access_t access)
|
|
{
|
|
struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
|
|
struct saa_driver *driver = sscreen->driver;
|
|
struct saa_pixmap *spix = saa_pixmap(pix);
|
|
saa_access_t unmap_access = 0;
|
|
|
|
if ((access & SAA_ACCESS_R) != 0 && --spix->read_access == 0)
|
|
unmap_access = SAA_ACCESS_R;
|
|
if ((access & SAA_ACCESS_W) != 0 && --spix->write_access == 0)
|
|
unmap_access |= SAA_ACCESS_W;
|
|
|
|
if (spix->read_access < 0)
|
|
LogMessage(X_ERROR, "Incorrect read access.\n");
|
|
if (spix->write_access < 0)
|
|
LogMessage(X_ERROR, "Incorrect write access.\n");
|
|
|
|
if (unmap_access) {
|
|
if (spix->auth_loc != saa_loc_override) {
|
|
driver->unmap(driver, pix, unmap_access);
|
|
driver->release_from_cpu(driver, pix, unmap_access);
|
|
}
|
|
spix->mapped_access &= ~unmap_access;
|
|
}
|
|
if (!spix->mapped_access) {
|
|
spix->addr = NULL;
|
|
pix->devPrivate.ptr = SAA_INVALID_ADDRESS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Callback that is called after a rendering operation. We try to
|
|
* determine whether it's a shadow damage or a hw damage and call the
|
|
* driver callback.
|
|
*/
|
|
|
|
static void
|
|
saa_report_damage(DamagePtr damage, RegionPtr reg, void *closure)
|
|
{
|
|
PixmapPtr pixmap = (PixmapPtr) closure;
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct saa_driver *driver = saa_screen(pixmap->drawable.pScreen)->driver;
|
|
|
|
if (spix->read_access || spix->write_access)
|
|
LogMessage(X_ERROR, "Damage report inside prepare access.\n");
|
|
|
|
driver->operation_complete(driver, pixmap);
|
|
DamageEmpty(damage);
|
|
}
|
|
|
|
/**
|
|
* saa_notify_destroy_damage - Handle destroy damage notification
|
|
*
|
|
* \param damage[in] damage Pointer to damage about to be destroyed
|
|
* \param closure[in] closure Closure.
|
|
*
|
|
* Makes sure that whatever code destroys a damage object clears the
|
|
* saa_pixmap damage pointer. This is extra protection. Typically
|
|
* saa_destroy_pixmap should be correct if the various subsystem
|
|
* DestroyPixmap functions are called in the right order.
|
|
*/
|
|
static void
|
|
saa_notify_destroy_damage(DamagePtr damage, void *closure)
|
|
{
|
|
PixmapPtr pixmap = (PixmapPtr) closure;
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
|
|
if (spix->damage == damage)
|
|
spix->damage = NULL;
|
|
}
|
|
|
|
Bool
|
|
saa_add_damage(PixmapPtr pixmap)
|
|
{
|
|
ScreenPtr pScreen = pixmap->drawable.pScreen;
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
|
|
if (spix->damage)
|
|
return TRUE;
|
|
|
|
spix->damage = DamageCreate(saa_report_damage, saa_notify_destroy_damage,
|
|
DamageReportRawRegion, TRUE, pScreen, pixmap);
|
|
if (!spix->damage)
|
|
return FALSE;
|
|
|
|
DamageRegister(&pixmap->drawable, spix->damage);
|
|
DamageSetReportAfterOp(spix->damage, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static inline RegionPtr
|
|
saa_pix_damage_region(struct saa_pixmap *spix)
|
|
{
|
|
return (spix->damage ? DamageRegion(spix->damage) : NULL);
|
|
}
|
|
|
|
Bool
|
|
saa_pad_read(DrawablePtr draw)
|
|
{
|
|
ScreenPtr pScreen = draw->pScreen;
|
|
PixmapPtr pix;
|
|
int xp;
|
|
int yp;
|
|
BoxRec box;
|
|
RegionRec entire;
|
|
Bool ret;
|
|
|
|
(void)pScreen;
|
|
pix = saa_get_pixmap(draw, &xp, &yp);
|
|
|
|
box.x1 = draw->x + xp;
|
|
box.y1 = draw->y + yp;
|
|
box.x2 = box.x1 + draw->width;
|
|
box.y2 = box.y1 + draw->height;
|
|
|
|
REGION_INIT(pScreen, &entire, &box, 1);
|
|
ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
|
|
REGION_UNINIT(pScreen, &entire);
|
|
return ret;
|
|
}
|
|
|
|
Bool
|
|
saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h)
|
|
{
|
|
ScreenPtr pScreen = draw->pScreen;
|
|
PixmapPtr pix;
|
|
int xp;
|
|
int yp;
|
|
BoxRec box;
|
|
RegionRec entire;
|
|
Bool ret;
|
|
|
|
(void)pScreen;
|
|
pix = saa_get_pixmap(draw, &xp, &yp);
|
|
|
|
box.x1 = x + xp;
|
|
box.y1 = y + yp;
|
|
box.x2 = box.x1 + w;
|
|
box.y2 = box.y1 + h;
|
|
|
|
REGION_INIT(pScreen, &entire, &box, 1);
|
|
ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
|
|
REGION_UNINIT(pScreen, &entire);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Prepares a drawable destination for access, and maps it read-write.
|
|
* If check_read is TRUE, pGC should point to a valid GC. The drawable
|
|
* may then be mapped write-only if the pending operation admits.
|
|
*/
|
|
|
|
Bool
|
|
saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
|
|
saa_access_t * access)
|
|
{
|
|
int xp;
|
|
int yp;
|
|
PixmapPtr pixmap = saa_get_pixmap(draw, &xp, &yp);
|
|
struct saa_pixmap *spix = saa_pixmap(pixmap);
|
|
|
|
*access = SAA_ACCESS_W;
|
|
|
|
/*
|
|
* If the to-be-damaged area doesn't depend at all on previous
|
|
* rendered contents, we don't need to do any readback.
|
|
*/
|
|
|
|
if (check_read && !saa_gc_reads_destination(draw, pGC))
|
|
return saa_prepare_access_pixmap(pixmap, *access, NULL);
|
|
|
|
*access |= SAA_ACCESS_R;
|
|
|
|
/*
|
|
* Read back the area to be damaged.
|
|
*/
|
|
|
|
return saa_prepare_access_pixmap(pixmap, *access,
|
|
saa_pix_damage_pending(spix));
|
|
}
|
|
|
|
void
|
|
saa_fad_read(DrawablePtr draw)
|
|
{
|
|
saa_finish_access_pixmap(saa_get_drawable_pixmap(draw), SAA_ACCESS_R);
|
|
}
|
|
|
|
void
|
|
saa_fad_write(DrawablePtr draw, saa_access_t access)
|
|
{
|
|
PixmapPtr pix = saa_get_drawable_pixmap(draw);
|
|
struct saa_pixmap *spix = saa_pixmap(pix);
|
|
|
|
saa_finish_access_pixmap(pix, access);
|
|
if (spix->damage)
|
|
saa_pixmap_dirty(pix, FALSE, saa_pix_damage_pending(spix));
|
|
}
|
|
|
|
Bool
|
|
saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC)
|
|
{
|
|
return ((pGC->alu != GXcopy && pGC->alu != GXclear && pGC->alu != GXset &&
|
|
pGC->alu != GXcopyInverted) || pGC->fillStyle == FillStippled ||
|
|
pGC->clientClip != NULL ||
|
|
!SAA_PM_IS_SOLID(pDrawable, pGC->planemask));
|
|
}
|
|
|
|
Bool
|
|
saa_op_reads_destination(CARD8 op)
|
|
{
|
|
/* FALSE (does not read destination) is the list of ops in the protocol
|
|
* document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
|
|
* That's just Clear and Src. ReduceCompositeOp() will already have
|
|
* converted con/disjoint clear/src to Clear or Src.
|
|
*/
|
|
switch (op) {
|
|
case PictOpClear:
|
|
case PictOpSrc:
|
|
return FALSE;
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
saa_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
|
|
{
|
|
/* fbValidateGC will do direct access to pixmaps if the tiling has changed.
|
|
* Do a few smart things so fbValidateGC can do it's work.
|
|
*/
|
|
|
|
ScreenPtr pScreen = pDrawable->pScreen;
|
|
struct saa_screen_priv *sscreen = saa_screen(pScreen);
|
|
struct saa_gc_priv *sgc = saa_gc(pGC);
|
|
PixmapPtr pTile = NULL;
|
|
Bool finish_current_tile = FALSE;
|
|
|
|
/* Either of these conditions is enough to trigger access to a tile pixmap. */
|
|
/* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
|
|
if (pGC->fillStyle == FillTiled
|
|
|| ((changes & GCTile) && !pGC->tileIsPixel)) {
|
|
pTile = pGC->tile.pixmap;
|
|
|
|
/* Sometimes tile pixmaps are swapped, you need access to:
|
|
* - The current tile if it depth matches.
|
|
* - Or the rotated tile if that one matches depth and !(changes & GCTile).
|
|
* - Or the current tile pixmap and a newly created one.
|
|
*/
|
|
if (pTile && pTile->drawable.depth != pDrawable->depth
|
|
&& !(changes & GCTile)) {
|
|
PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);
|
|
|
|
if (pRotatedTile
|
|
&& pRotatedTile->drawable.depth == pDrawable->depth)
|
|
pTile = pRotatedTile;
|
|
else
|
|
finish_current_tile = TRUE; /* CreatePixmap will be called. */
|
|
}
|
|
}
|
|
|
|
if (pGC->stipple && !saa_pad_read(&pGC->stipple->drawable)) {
|
|
LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
|
|
return;
|
|
}
|
|
|
|
if (pTile && !saa_pad_read(&pTile->drawable)) {
|
|
LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
|
|
goto out_no_tile;
|
|
}
|
|
|
|
/* Calls to Create/DestroyPixmap have to be identified as special, so
|
|
* up sscreen->fallback_count.
|
|
*/
|
|
|
|
sscreen->fallback_count++;
|
|
saa_swap(sgc, pGC, funcs);
|
|
(*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
|
|
saa_swap(sgc, pGC, funcs);
|
|
|
|
if (finish_current_tile && pGC->tile.pixmap)
|
|
saa_fad_write(&pGC->tile.pixmap->drawable, SAA_ACCESS_W);
|
|
sscreen->fallback_count--;
|
|
|
|
if (pTile)
|
|
saa_fad_read(&pTile->drawable);
|
|
out_no_tile:
|
|
if (pGC->stipple)
|
|
saa_fad_read(&pGC->stipple->drawable);
|
|
}
|
|
|
|
static void
|
|
saa_destroy_gc(GCPtr pGC)
|
|
{
|
|
struct saa_gc_priv *sgc = saa_gc(pGC);
|
|
|
|
saa_swap(sgc, pGC, funcs);
|
|
(*pGC->funcs->DestroyGC) (pGC);
|
|
saa_swap(sgc, pGC, funcs);
|
|
}
|
|
|
|
static void
|
|
saa_change_gc(GCPtr pGC, unsigned long mask)
|
|
{
|
|
struct saa_gc_priv *sgc = saa_gc(pGC);
|
|
|
|
saa_swap(sgc, pGC, funcs);
|
|
(*pGC->funcs->ChangeGC) (pGC, mask);
|
|
saa_swap(sgc, pGC, funcs);
|
|
}
|
|
|
|
static void
|
|
saa_copy_gc(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
|
|
{
|
|
struct saa_gc_priv *sgc = saa_gc(pGCDst);
|
|
|
|
saa_swap(sgc, pGCDst, funcs);
|
|
(*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
|
|
saa_swap(sgc, pGCDst, funcs);
|
|
}
|
|
|
|
static void
|
|
saa_change_clip(GCPtr pGC, int type, pointer pvalue, int nrects)
|
|
{
|
|
struct saa_gc_priv *sgc = saa_gc(pGC);
|
|
|
|
saa_swap(sgc, pGC, funcs);
|
|
(*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
|
|
saa_swap(sgc, pGC, funcs);
|
|
}
|
|
|
|
static void
|
|
saa_copy_clip(GCPtr pGCDst, GCPtr pGCSrc)
|
|
{
|
|
struct saa_gc_priv *sgc = saa_gc(pGCDst);
|
|
|
|
saa_swap(sgc, pGCDst, funcs);
|
|
(*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
|
|
saa_swap(sgc, pGCDst, funcs);
|
|
}
|
|
|
|
static void
|
|
saa_destroy_clip(GCPtr pGC)
|
|
{
|
|
struct saa_gc_priv *sgc = saa_gc(pGC);
|
|
|
|
saa_swap(sgc, pGC, funcs);
|
|
(*pGC->funcs->DestroyClip) (pGC);
|
|
saa_swap(sgc, pGC, funcs);
|
|
}
|
|
|
|
static GCFuncs saa_gc_funcs = {
|
|
saa_validate_gc,
|
|
saa_change_gc,
|
|
saa_copy_gc,
|
|
saa_destroy_gc,
|
|
saa_change_clip,
|
|
saa_destroy_clip,
|
|
saa_copy_clip
|
|
};
|
|
|
|
/**
|
|
* saa_create_gc makes a new GC and hooks up its funcs handler, so that
|
|
* saa_validate_gc() will get called.
|
|
*/
|
|
int
|
|
saa_create_gc(GCPtr pGC)
|
|
{
|
|
ScreenPtr pScreen = pGC->pScreen;
|
|
struct saa_screen_priv *sscreen = saa_screen(pScreen);
|
|
struct saa_gc_priv *sgc = saa_gc(pGC);
|
|
Bool ret;
|
|
|
|
saa_swap(sscreen, pScreen, CreateGC);
|
|
ret = pScreen->CreateGC(pGC);
|
|
if (ret) {
|
|
saa_wrap(sgc, pGC, funcs, &saa_gc_funcs);
|
|
saa_wrap(sgc, pGC, ops, &saa_gc_ops);
|
|
}
|
|
saa_swap(sscreen, pScreen, CreateGC);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static Bool
|
|
saa_prepare_access_window(WindowPtr pWin)
|
|
{
|
|
if (pWin->backgroundState == BackgroundPixmap) {
|
|
if (!saa_pad_read(&pWin->background.pixmap->drawable))
|
|
return FALSE;
|
|
}
|
|
|
|
if (pWin->borderIsPixel == FALSE) {
|
|
if (!saa_pad_read(&pWin->border.pixmap->drawable)) {
|
|
if (pWin->backgroundState == BackgroundPixmap)
|
|
saa_fad_read(&pWin->background.pixmap->drawable);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
saa_finish_access_window(WindowPtr pWin)
|
|
{
|
|
if (pWin->backgroundState == BackgroundPixmap)
|
|
saa_fad_read(&pWin->background.pixmap->drawable);
|
|
|
|
if (pWin->borderIsPixel == FALSE)
|
|
saa_fad_read(&pWin->border.pixmap->drawable);
|
|
}
|
|
|
|
static Bool
|
|
saa_change_window_attributes(WindowPtr pWin, unsigned long mask)
|
|
{
|
|
Bool ret;
|
|
|
|
if (!saa_prepare_access_window(pWin))
|
|
return FALSE;
|
|
ret = fbChangeWindowAttributes(pWin, mask);
|
|
saa_finish_access_window(pWin);
|
|
return ret;
|
|
}
|
|
|
|
RegionPtr
|
|
saa_bitmap_to_region(PixmapPtr pPix)
|
|
{
|
|
RegionPtr ret;
|
|
|
|
if (!saa_pad_read(&pPix->drawable))
|
|
return NULL;
|
|
ret = fbPixmapToRegion(pPix);
|
|
saa_fad_read(&pPix->drawable);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
saa_set_fallback_debug(ScreenPtr screen, Bool enable)
|
|
{
|
|
struct saa_screen_priv *sscreen = saa_screen(screen);
|
|
|
|
sscreen->fallback_debug = enable;
|
|
}
|
|
|
|
/**
|
|
* saa_early_close_screen() Makes sure we call saa_destroy_pixmap on the
|
|
* miScreenInit() pixmap _before_ damageCloseScreen, after which it will
|
|
* generate an invalid memory access. Also unwraps the functions we
|
|
* wrapped _after_ DamageSetup().
|
|
*/
|
|
static Bool
|
|
saa_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
|
|
{
|
|
struct saa_screen_priv *sscreen = saa_screen(pScreen);
|
|
|
|
if (pScreen->devPrivate) {
|
|
/* Destroy the pixmap created by miScreenInit() *before*
|
|
* chaining up as we finalize ourselves here and so this
|
|
* is the last chance we have of releasing our resources
|
|
* associated with the Pixmap. So do it first.
|
|
*/
|
|
dixPixmapPut(pScreen->devPrivate);
|
|
pScreen->devPrivate = NULL;
|
|
}
|
|
|
|
saa_unwrap_early(sscreen, pScreen, CloseScreen);
|
|
saa_unwrap(sscreen, pScreen, DestroyPixmap);
|
|
|
|
return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
|
|
}
|
|
|
|
/**
|
|
* saa_close_screen() unwraps its wrapped screen functions and tears down SAA's
|
|
* screen private, before calling down to the next CloseScreen.
|
|
*/
|
|
Bool
|
|
saa_close_screen(CLOSE_SCREEN_ARGS_DECL)
|
|
{
|
|
struct saa_screen_priv *sscreen = saa_screen(pScreen);
|
|
struct saa_driver *driver = sscreen->driver;
|
|
|
|
saa_unwrap(sscreen, pScreen, CloseScreen);
|
|
saa_unwrap(sscreen, pScreen, CreateGC);
|
|
saa_unwrap(sscreen, pScreen, ChangeWindowAttributes);
|
|
saa_unwrap(sscreen, pScreen, CreatePixmap);
|
|
saa_unwrap(sscreen, pScreen, ModifyPixmapHeader);
|
|
saa_unwrap(sscreen, pScreen, BitmapToRegion);
|
|
#ifdef RENDER
|
|
saa_render_takedown(pScreen);
|
|
#endif
|
|
saa_unaccel_takedown(pScreen);
|
|
driver->takedown(driver);
|
|
|
|
free(sscreen);
|
|
|
|
return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
|
|
}
|
|
|
|
struct saa_driver *
|
|
saa_get_driver(ScreenPtr pScreen)
|
|
{
|
|
return saa_screen(pScreen)->driver;
|
|
}
|
|
|
|
/**
|
|
* @param pScreen screen being initialized
|
|
* @param pScreenInfo SAA driver record
|
|
*
|
|
* saa_driver_init sets up SAA given a driver record filled in by the driver.
|
|
* pScreenInfo should have been allocated by saa_driver_alloc(). See the
|
|
* comments in _SaaDriver for what must be filled in and what is optional.
|
|
*
|
|
* @return TRUE if SAA was successfully initialized.
|
|
*/
|
|
Bool
|
|
saa_driver_init(ScreenPtr screen, struct saa_driver * saa_driver)
|
|
{
|
|
struct saa_screen_priv *sscreen;
|
|
|
|
if (!saa_driver)
|
|
return FALSE;
|
|
|
|
if (saa_driver->saa_major != SAA_VERSION_MAJOR ||
|
|
saa_driver->saa_minor > SAA_VERSION_MINOR) {
|
|
LogMessage(X_ERROR,
|
|
"SAA(%d): driver's SAA version requirements "
|
|
"(%d.%d) are incompatible with SAA version (%d.%d)\n",
|
|
screen->myNum, saa_driver->saa_major,
|
|
saa_driver->saa_minor, SAA_VERSION_MAJOR, SAA_VERSION_MINOR);
|
|
return FALSE;
|
|
}
|
|
#if 0
|
|
if (!saa_driver->prepare_solid) {
|
|
LogMessage(X_ERROR,
|
|
"SAA(%d): saa_driver_t::prepare_solid must be "
|
|
"non-NULL\n", screen->myNum);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!saa_driver->prepare_copy) {
|
|
LogMessage(X_ERROR,
|
|
"SAA(%d): saa_driver_t::prepare_copy must be "
|
|
"non-NULL\n", screen->myNum);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
if (!dixRegisterPrivateKey(&saa_screen_index, PRIVATE_SCREEN, 0)) {
|
|
LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
|
|
return FALSE;
|
|
}
|
|
if (!dixRegisterPrivateKey(&saa_pixmap_index, PRIVATE_PIXMAP,
|
|
saa_driver->pixmap_size)) {
|
|
LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
|
|
return FALSE;
|
|
}
|
|
if (!dixRegisterPrivateKey(&saa_gc_index, PRIVATE_GC,
|
|
sizeof(struct saa_gc_priv))) {
|
|
LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
sscreen = calloc(1, sizeof(*sscreen));
|
|
|
|
if (!sscreen) {
|
|
LogMessage(X_WARNING,
|
|
"SAA(%d): Failed to allocate screen private\n",
|
|
screen->myNum);
|
|
return FALSE;
|
|
}
|
|
|
|
sscreen->driver = saa_driver;
|
|
dixSetPrivate(&screen->devPrivates, &saa_screen_index, sscreen);
|
|
|
|
/*
|
|
* Replace various fb screen functions
|
|
*/
|
|
|
|
saa_wrap(sscreen, screen, CloseScreen, saa_close_screen);
|
|
saa_wrap(sscreen, screen, CreateGC, saa_create_gc);
|
|
saa_wrap(sscreen, screen, ChangeWindowAttributes,
|
|
saa_change_window_attributes);
|
|
saa_wrap(sscreen, screen, CreatePixmap, saa_create_pixmap);
|
|
saa_wrap(sscreen, screen, ModifyPixmapHeader, saa_modify_pixmap_header);
|
|
saa_wrap(sscreen, screen, BitmapToRegion, saa_bitmap_to_region);
|
|
saa_unaccel_setup(screen);
|
|
#ifdef RENDER
|
|
saa_render_setup(screen);
|
|
#endif
|
|
|
|
/*
|
|
* Correct saa functionality relies on Damage, so set it up now.
|
|
* Note that this must happen _after_ wrapping the rendering functionality
|
|
* so that damage happens outside of saa.
|
|
*/
|
|
if (!DamageSetup(screen))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Wrap DestroyPixmap after DamageSetup, so that saa_destroy_pixmap is
|
|
* called _before_ damageDestroyPixmap. This is to make damageDestroyPixmap
|
|
* doesn't free objects pointed to by our damage pointers.
|
|
*
|
|
* Also wrap an early CloseScreen to perform actions needed to be done
|
|
* before damageCloseScreen and to unwrap DestroyPixmap correctly.
|
|
*/
|
|
saa_wrap(sscreen, screen, DestroyPixmap, saa_destroy_pixmap);
|
|
saa_wrap_early(sscreen, screen, CloseScreen, saa_early_close_screen);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
saa_resources_init(ScreenPtr screen)
|
|
{
|
|
/* if (!saa_glyphs_init(screen))
|
|
return FALSE;
|
|
*/
|
|
return TRUE;
|
|
}
|