vmwgfx_xa_surface.c revision 22f7e8e5
1/*
2 * Copyright 2011 VMWare, Inc.
3 * 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: Thomas Hellstrom <thellstrom@vmware.com>
26 */
27#ifdef _HAVE_CONFIG_H_
28#include "config.h"
29#endif
30
31#include <xorg-server.h>
32#include "vmwgfx_saa_priv.h"
33
34
35static const enum xa_surface_type vmwgfx_stype_map[] = {
36  [PICT_TYPE_OTHER] = xa_type_other,
37  [PICT_TYPE_A] = xa_type_a,
38  [PICT_TYPE_ARGB] = xa_type_argb,
39  [PICT_TYPE_ABGR] = xa_type_abgr,
40  [PICT_TYPE_BGRA] = xa_type_bgra
41};
42
43static const unsigned int vmwgfx_stype_map_size =
44    sizeof(vmwgfx_stype_map) / sizeof(enum xa_surface_type);
45
46
47/*
48 * Create an xa format from a PICT format.
49 */
50enum xa_formats
51vmwgfx_xa_format(enum _PictFormatShort format)
52{
53    uint32_t ptype = PICT_FORMAT_TYPE(format);
54
55    if (ptype >= vmwgfx_stype_map_size ||
56	vmwgfx_stype_map[ptype] == 0 ||
57	vmwgfx_stype_map[ptype] == xa_type_other)
58	return xa_format_unknown;
59
60    return xa_format(PICT_FORMAT_BPP(format),
61		     vmwgfx_stype_map[ptype],
62		     PICT_FORMAT_A(format),
63		     PICT_FORMAT_R(format),
64		     PICT_FORMAT_G(format),
65		     PICT_FORMAT_B(format));
66}
67
68/*
69 * Choose formats and flags for a dri2 surface.
70 */
71static Bool
72vmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth)
73{
74    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
75    enum xa_formats format;
76
77    if (depth == 0)
78	depth = pixmap->drawable.depth;
79
80    switch(depth) {
81    case 32:
82	format = xa_format_a8r8g8b8;
83	break;
84    case 24:
85        format = xa_format_x8r8g8b8;
86	break;
87    case 16:
88	format = xa_format_r5g6b5;
89	break;
90    case 15:
91	format = xa_format_x1r5g5b5;
92	break;
93    default:
94	return FALSE;
95    }
96
97    vpix->staging_format = format;
98    vpix->staging_remove_flags = 0;
99    vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED;
100
101    return TRUE;
102}
103
104/*
105 * Is composite old format compatible? Only difference is that old format
106 * has more alpha bits?
107 */
108static inline Bool
109vmwgfx_old_format_compatible(enum xa_formats format,
110			     enum xa_formats old_format)
111{
112    return (format == old_format ||
113	    (xa_format_type(format) == xa_format_type(old_format) &&
114	     xa_format_a(format) <= xa_format_a(old_format) &&
115	     xa_format_r(format) == xa_format_r(old_format) &&
116	     xa_format_g(format) == xa_format_g(old_format) &&
117	     xa_format_b(format) == xa_format_b(old_format)));
118}
119
120
121/*
122 * Choose format and flags for a composite dst surface.
123 */
124Bool
125vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap,
126			      enum _PictFormatShort pict_format)
127{
128    struct vmwgfx_saa *vsaa =
129	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
130    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
131    enum xa_formats format = vmwgfx_xa_format(pict_format);
132
133    /*
134     * Check if we can reuse old hardware format.
135     */
136    if (vpix->hw) {
137	enum xa_formats old_format = xa_surface_format(vpix->hw);
138
139	if (vmwgfx_old_format_compatible(format, old_format))
140	    format = old_format;
141    }
142
143    if (xa_format_check_supported(vsaa->xat, format,
144				  vpix->xa_flags | XA_FLAG_RENDER_TARGET) !=
145	XA_ERR_NONE) {
146	return FALSE;
147    }
148
149    vpix->staging_format = format;
150    vpix->staging_remove_flags = 0;
151    vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED;
152
153    return TRUE;
154}
155
156/*
157 * Choose format and flags for a composite src surface.
158 */
159Bool
160vmwgfx_hw_composite_src_stage(PixmapPtr pixmap,
161			      enum _PictFormatShort pict_format)
162{
163    struct vmwgfx_saa *vsaa =
164	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
165    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
166    enum xa_formats format = vmwgfx_xa_format(pict_format);
167    enum xa_formats swizzle_format = xa_format_unknown;
168    enum xa_surface_type ftype;
169
170    if (format == xa_format_unknown)
171	return FALSE;
172
173    ftype = xa_format_type(format);
174    if (ftype == xa_type_abgr) {
175
176	swizzle_format = xa_format(xa_format_bpp(format),
177				   xa_type_argb,
178				   xa_format_a(format),
179				   xa_format_r(format),
180				   xa_format_g(format),
181				   xa_format_b(format));
182    }
183
184    /*
185     * Check if we can reuse old format.
186     */
187
188    if (vpix->hw) {
189	enum xa_formats old_format = xa_surface_format(vpix->hw);
190
191	if (vmwgfx_old_format_compatible(format, old_format) ||
192	    (swizzle_format != xa_format_unknown &&
193	     vmwgfx_old_format_compatible(swizzle_format, old_format))) {
194	    format = old_format;
195	    goto have_format;
196	}
197    }
198
199    if (swizzle_format != xa_format_unknown &&
200	xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) ==
201	XA_ERR_NONE) {
202	format = swizzle_format;
203	goto have_format;
204    }
205
206    if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) ==
207	XA_ERR_NONE) {
208	goto have_format;
209    }
210
211    return FALSE;
212  have_format:
213    vpix->staging_format = format;
214    vpix->staging_remove_flags = 0;
215    vpix->staging_add_flags = 0;
216
217    return TRUE;
218}
219
220/*
221 * Choose accel format given depth.
222 */
223static enum xa_formats
224vmwgfx_choose_accel_format(unsigned int depth)
225{
226    switch(depth) {
227    case 32:
228	return xa_format_a8r8g8b8;
229    case 24:
230	return xa_format_x8r8g8b8;
231    case 16:
232	return xa_format_r5g6b5;
233    case 15:
234	return xa_format_x1r5g5b5;
235    case 8:
236	return xa_format_a8;
237    default:
238	break;
239    }
240    return xa_format_unknown;
241}
242
243
244/*
245 * Determine xa format and flags for an ordinary accel surface.
246 */
247Bool
248vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth,
249		      uint32_t add_flags, uint32_t remove_flags)
250{
251    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
252    enum xa_formats format = xa_format_unknown;
253
254    if (depth == 0)
255	depth = pixmap->drawable.depth;
256
257    if (vpix->hw) {
258	enum xa_formats old_format = xa_surface_format(vpix->hw);
259	enum xa_surface_type ftype = xa_format_type(old_format);
260
261	if (ftype != xa_type_argb &&
262	    ftype != xa_type_a) {
263	    LogMessage(X_ERROR,
264		       "Acceleration fallback due to strange hw format.\n");
265	    return FALSE;
266	}
267
268	if (xa_format_depth(old_format) == depth ||
269	    (xa_format_depth(old_format) == 32 &&
270	     depth == 24))
271	    format = old_format;
272    }
273
274    if (format == xa_format_unknown)
275	format = vmwgfx_choose_accel_format(depth);
276
277    if (format == xa_format_unknown)
278	return FALSE;
279
280    vpix->staging_add_flags = add_flags;
281    vpix->staging_remove_flags = remove_flags;
282    vpix->staging_format = format;
283
284    return TRUE;
285}
286
287/*
288 * Create a surface with a format and flags determined by one of
289 * the staging functions.
290 */
291Bool
292vmwgfx_hw_commit(PixmapPtr pixmap)
293{
294    struct vmwgfx_saa *vsaa =
295	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
296    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
297    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
298    enum xa_formats format = vpix->staging_format;
299
300    if (vpix->hw) {
301	enum xa_formats old_format = xa_surface_format(vpix->hw);
302
303	if (vpix->staging_format != old_format) {
304	    if (xa_format_type(format) != xa_format_type(old_format) ||
305		xa_format_r(format) != xa_format_r(old_format) ||
306		xa_format_g(format) != xa_format_g(old_format) ||
307		xa_format_b(format) != xa_format_b(old_format)) {
308
309		LogMessage(X_INFO, "Killing old hw surface.\n");
310
311		if (!vmwgfx_hw_kill(vsaa, spix))
312		    return FALSE;
313	    }
314	}
315    }
316
317    if (vpix->hw) {
318	uint32_t new_flags;
319
320	new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) |
321	    vpix->staging_add_flags | XA_FLAG_SHARED;
322
323	if (vpix->staging_format != xa_surface_format(vpix->hw))
324	    LogMessage(X_INFO, "Changing hardware format.\n");
325
326	if (xa_surface_redefine(vpix->hw,
327				pixmap->drawable.width,
328				pixmap->drawable.height,
329				0,
330				xa_type_other,
331				vpix->staging_format,
332				new_flags, 1) != XA_ERR_NONE)
333	    return FALSE;
334	vpix->xa_flags = new_flags;
335    } else if (!vmwgfx_create_hw(vsaa, pixmap))
336	return FALSE;
337
338    return TRUE;
339}
340
341/*
342 * Create an accel surface if there is none, and make sure the region
343 * given by @region is valid. If @region is NULL, the whole surface
344 * will be valid. This is a utility convenience function only.
345 */
346Bool
347vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth,
348			 uint32_t add_flags, uint32_t remove_flags,
349			 RegionPtr region)
350{
351    return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) &&
352	    vmwgfx_hw_commit(pixmap) &&
353	    vmwgfx_hw_validate(pixmap, region));
354}
355
356
357/*
358 * Create a dri2 surface if there is none,
359 * and make sure the whole surfade is valid.
360 * This is a utility convenience function only.
361 */
362Bool
363vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth)
364{
365    struct vmwgfx_saa *vsaa =
366	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
367
368    if (!vsaa->is_master)
369	    return FALSE;
370
371    return (vmwgfx_hw_dri2_stage(pixmap, depth) &&
372	    vmwgfx_hw_commit(pixmap) &&
373	    vmwgfx_hw_validate(pixmap, NULL));
374}
375