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