1/*
2 * Copyright © 2009 Maarten Maathuis
3 * Copyright 2011 VMWare, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Author: Based on "exa_driver.c"
26 * Author: Thomas Hellstrom <thellstrom@vmware.com>
27 */
28
29#include "saa_priv.h"
30#include "saa.h"
31
32PixmapPtr
33saa_create_pixmap(ScreenPtr pScreen, int w, int h, int depth,
34		  unsigned usage_hint)
35{
36    PixmapPtr pPixmap;
37    struct saa_pixmap *spix;
38    int bpp;
39    size_t paddedWidth;
40    struct saa_screen_priv *sscreen = saa_screen(pScreen);
41    int new_pitch = 0;
42    struct saa_driver *driver = sscreen->driver;
43
44    if (w > 32767 || h > 32767)
45	return NullPixmap;
46
47    /*
48     * Create a scratch pixmap without backing storage (w and h are zero)
49     */
50
51    saa_swap(sscreen, pScreen, CreatePixmap);
52    pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
53    saa_swap(sscreen, pScreen, CreatePixmap);
54
55    if (!pPixmap)
56	goto out_no_pix;
57
58    spix = saa_pixmap(pPixmap);
59    memset(spix, 0, driver->pixmap_size);
60    REGION_NULL(pScreen, &spix->dirty_shadow);
61    REGION_NULL(pScreen, &spix->dirty_hw);
62    REGION_NULL(pScreen, &spix->shadow_damage);
63    spix->read_access = 0;
64    spix->write_access = 0;
65    spix->mapped_access = 0;
66    spix->addr = NULL;
67    spix->auth_loc = saa_loc_override;
68    spix->override = SAA_INVALID_ADDRESS;
69    spix->pixmap = pPixmap;
70    bpp = pPixmap->drawable.bitsPerPixel;
71
72    if (!driver->create_pixmap(driver, spix, w, h, depth,
73			       usage_hint, bpp, &new_pitch))
74	goto out_no_driver_priv;
75
76    paddedWidth = new_pitch;
77    spix->damage = NULL;
78
79    /*
80     * Now set w and h to the correct value. This might allocate
81     * backing store if w and h are NON-NULL.
82     */
83
84    if (!(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0,
85					 paddedWidth, NULL))
86	goto out_no_pixmap_header;
87
88    /*
89     * During a fallback we must prepare access. This hack is initially used
90     * for pixmaps created during ValidateGC.
91     */
92
93    spix->fallback_created = FALSE;
94    if (sscreen->fallback_count) {
95	if (!saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_W, NULL))
96	    goto out_no_access;
97
98	spix->fallback_created = TRUE;
99    }
100
101    return pPixmap;
102 out_no_access:
103 out_no_pixmap_header:
104    driver->destroy_pixmap(driver, pPixmap);
105 out_no_driver_priv:
106    saa_swap(sscreen, pScreen, DestroyPixmap);
107    pScreen->DestroyPixmap(pPixmap);
108    saa_swap(sscreen, pScreen, DestroyPixmap);
109 out_no_pix:
110    LogMessage(X_ERROR, "Failing pixmap creation.\n");
111    return NullPixmap;
112}
113
114Bool
115saa_destroy_pixmap(PixmapPtr pPixmap)
116{
117    ScreenPtr pScreen = pPixmap->drawable.pScreen;
118    struct saa_screen_priv *sscreen = saa_screen(pScreen);
119    Bool ret;
120    struct saa_driver *driver = sscreen->driver;
121
122    if (pPixmap->refcnt == 1) {
123	struct saa_pixmap *spix = saa_pixmap(pPixmap);
124
125	if (spix->fallback_created) {
126	    if (!sscreen->fallback_count)
127		LogMessage(X_ERROR, "Fallback pixmap destroyed outside "
128			   "fallback.\n");
129
130	    saa_finish_access_pixmap(pPixmap, SAA_ACCESS_W);
131	}
132
133	driver->destroy_pixmap(driver, pPixmap);
134
135	REGION_UNINIT(pScreen, &spix->dirty_hw);
136	REGION_UNINIT(pScreen, &spix->dirty_shadow);
137	if (spix->damage)
138	    DamageDestroy(spix->damage);
139    }
140
141    saa_swap(sscreen, pScreen, DestroyPixmap);
142    ret = pScreen->DestroyPixmap(pPixmap);
143    saa_swap(sscreen, pScreen, DestroyPixmap);
144
145    return ret;
146}
147
148Bool
149saa_modify_pixmap_header(PixmapPtr pPixmap, int width, int height, int depth,
150			 int bitsPerPixel, int devKind, pointer pPixData)
151{
152    ScreenPtr pScreen;
153    struct saa_screen_priv *sscreen;
154    struct saa_pixmap *spix;
155    struct saa_driver *driver;
156    Bool ret = TRUE;
157
158    if (!pPixmap)
159	return FALSE;
160
161    pScreen = pPixmap->drawable.pScreen;
162    sscreen = saa_screen(pScreen);
163    spix = saa_pixmap(pPixmap);
164    driver = sscreen->driver;
165
166    if (spix && driver->modify_pixmap_header &&
167	driver->modify_pixmap_header(pPixmap, width, height, depth,
168				     bitsPerPixel, devKind, pPixData)) {
169	spix->auth_loc = saa_loc_driver;
170	spix->override = SAA_INVALID_ADDRESS;
171	goto out;
172    }
173
174    saa_swap(sscreen, pScreen, ModifyPixmapHeader);
175    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
176				      bitsPerPixel, devKind, pPixData);
177    saa_swap(sscreen, pScreen, ModifyPixmapHeader);
178    spix->override = pPixmap->devPrivate.ptr;
179    spix->auth_loc = saa_loc_override;
180
181 out:
182    pPixmap->devPrivate.ptr = NULL;
183    return ret;
184}
185
186struct saa_pixmap *
187saa_get_saa_pixmap(PixmapPtr pPixmap)
188{
189    return saa_pixmap(pPixmap);
190}
191
192void
193saa_pixmap_dirty(PixmapPtr pixmap, Bool hw, RegionPtr reg)
194{
195    struct saa_pixmap *spix = saa_pixmap(pixmap);
196    struct saa_screen_priv *sscreen = saa_screen(pixmap->drawable.pScreen);
197
198    if (hw) {
199	REGION_UNION(pixmap->drawable.pScreen, &spix->dirty_hw,
200		     &spix->dirty_hw, reg);
201	REGION_SUBTRACT(pixmap->drawable.pScreen, &spix->dirty_shadow,
202			&spix->dirty_shadow, reg);
203    } else {
204	REGION_UNION(pixmap->drawable.pScreen, &spix->dirty_shadow,
205		     &spix->dirty_shadow, reg);
206	REGION_SUBTRACT(pixmap->drawable.pScreen, &spix->dirty_hw,
207			&spix->dirty_hw, reg);
208    }
209
210    sscreen->driver->damage(sscreen->driver, pixmap, hw, reg);
211}
212
213void
214saa_drawable_dirty(DrawablePtr draw, Bool hw, RegionPtr reg)
215{
216    PixmapPtr pixmap;
217    int x_offset, y_offset;
218
219    pixmap = saa_get_pixmap(draw, &x_offset, &y_offset);
220    REGION_TRANSLATE(draw->pScreen, reg, x_offset, y_offset);
221    saa_pixmap_dirty(pixmap, hw, reg);
222    REGION_TRANSLATE(draw->pScreen, reg, -x_offset, -y_offset);
223}
224