5fe5403a8586b43512343d2e4d3277b7c5f3f321
[platform/core/uifw/libtdm.git] / src / tdm_helper.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <boram1288.park@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <png.h>
41 #include <pixman.h>
42
43 #include "tdm_private.h"
44
45 #define PNG_DEPTH 8
46
47 static const char *file_exts[2] = {"png", "raw"};
48
49 int tdm_dump_enable;
50 char *tdm_debug_dump_dir;
51
52 EXTERN double
53 tdm_helper_get_time(void)
54 {
55         struct timespec tp;
56
57         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
58                 return (double)tp.tv_sec + ((double)tp.tv_nsec) / 1000000000.0;
59
60         return 0;
61 }
62
63 static int
64 _tdm_helper_check_file_is_symbolic_link(const char* path)
65 {
66         struct stat sb;
67
68         if (!path)
69                 return 0;
70
71         if (stat(path, &sb) != 0)
72                 return 0;
73
74         if (S_ISLNK(sb.st_mode))
75                 return 1;
76
77         return 0;
78 }
79
80 static void
81 _tdm_helper_dump_raw(const char *file, void *data1, int size1, void *data2,
82                                          int size2, void *data3, int size3)
83 {
84         unsigned int *blocks;
85         FILE *fp;
86
87         if (_tdm_helper_check_file_is_symbolic_link(file)) {
88                 TDM_ERR("'%s' may be symbolic link\n", file);
89                 return;
90         }
91
92         fp = fopen(file, "w+");
93         TDM_RETURN_IF_FAIL(fp != NULL);
94
95         blocks = (unsigned int *)data1;
96         fwrite(blocks, 1, size1, fp);
97
98         if (size2 > 0) {
99                 blocks = (unsigned int *)data2;
100                 fwrite(blocks, 1, size2, fp);
101         }
102
103         if (size3 > 0) {
104                 blocks = (unsigned int *)data3;
105                 fwrite(blocks, 1, size3, fp);
106         }
107
108         fclose(fp);
109 }
110
111 static void
112 _tdm_helper_dump_png(const char *file, const void *data, int width,
113                                          int height)
114 {
115         FILE *fp;
116
117         if (_tdm_helper_check_file_is_symbolic_link(file)) {
118                 TDM_ERR("'%s' may be symbolic link\n", file);
119                 return;
120         }
121
122         fp = fopen(file, "wb");
123         TDM_RETURN_IF_FAIL(fp != NULL);
124
125         png_structp pPngStruct =
126                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
127         if (!pPngStruct) {
128                 fclose(fp);
129                 return;
130         }
131
132         png_infop pPngInfo = png_create_info_struct(pPngStruct);
133         if (!pPngInfo) {
134                 png_destroy_write_struct(&pPngStruct, NULL);
135                 fclose(fp);
136                 return;
137         }
138
139         if (setjmp(png_jmpbuf(pPngStruct))) {
140                 /* if png has problem of writing the file, we get here */
141                 png_destroy_write_struct(&pPngStruct, &pPngInfo);
142                 fclose(fp);
143                 return;
144         }
145
146         png_init_io(pPngStruct, fp);
147         png_set_IHDR(pPngStruct,
148                                  pPngInfo,
149                                  width,
150                                  height,
151                                  PNG_DEPTH,
152                                  PNG_COLOR_TYPE_RGBA,
153                                  PNG_INTERLACE_NONE,
154                                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
155
156         png_set_bgr(pPngStruct);
157         png_write_info(pPngStruct, pPngInfo);
158
159         const int pixel_size = 4;       // RGBA
160         png_bytep *row_pointers =
161                 png_malloc(pPngStruct, height * sizeof(png_byte *));
162         if (!row_pointers) {
163                 png_destroy_write_struct(&pPngStruct, &pPngInfo);
164                 fclose(fp);
165                 return;
166         }
167
168         unsigned int *blocks = (unsigned int *)data;
169         int y = 0;
170         int x = 0;
171
172         for (; y < height; ++y) {
173                 png_bytep row =
174                         png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
175                 if (!row) {
176                         for (x = 0; x < y; x++)
177                                 png_free(pPngStruct, row_pointers[x]);
178                         png_free(pPngStruct, row_pointers);
179                         png_destroy_write_struct(&pPngStruct, &pPngInfo);
180                         fclose(fp);
181                         return;
182                 }
183
184                 row_pointers[y] = (png_bytep)row;
185                 for (x = 0; x < width; ++x) {
186                         unsigned int curBlock = blocks[y * width + x];
187                         row[x * pixel_size] = (curBlock & 0xFF);
188                         row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
189                         row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
190                         row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
191                 }
192         }
193
194         png_write_image(pPngStruct, row_pointers);
195         png_write_end(pPngStruct, pPngInfo);
196
197         for (y = 0; y < height; y++)
198                 png_free(pPngStruct, row_pointers[y]);
199         png_free(pPngStruct, row_pointers);
200
201         png_destroy_write_struct(&pPngStruct, &pPngInfo);
202
203         fclose(fp);
204 }
205
206 /* LCOV_EXCL_START */
207 INTERN char *
208 tdm_helper_dump_make_directory(const char *path, char *reply, int *len)
209 {
210         char *fullpath = NULL;
211         time_t timer;
212         struct tm *t, *buf = NULL;
213
214         timer = time(NULL);
215
216         buf = calloc(1, sizeof(struct tm));
217         TDM_GOTO_IF_FAIL(buf != NULL, failed_make);
218
219         fullpath = calloc(1, TDM_PATH_LEN * sizeof(char));
220         TDM_GOTO_IF_FAIL(fullpath != NULL, failed_make);
221
222         t = localtime_r(&timer, buf);
223         TDM_GOTO_IF_FAIL(t != NULL, failed_make);
224
225         snprintf(fullpath, TDM_PATH_LEN, "%s/dump_%04d%02d%02d.%02d%02d%02d", path,
226                          t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
227
228         if ((mkdir(fullpath, 0755)) < 0) {
229                 TDM_ERR("mkdir '%s' fail\n", fullpath);
230                 TDM_SNPRINTF(reply, len, "mkdir '%s' fail\n", fullpath);
231                 goto failed_make;
232         }
233
234         free(buf);
235
236         return fullpath;
237 failed_make:
238         if (fullpath)
239                 free(fullpath);
240         if (buf)
241                 free(buf);
242         return NULL;
243 }
244
245 EXTERN void
246 tdm_helper_dump_buffer_str(tbm_surface_h buffer, char *dir, char *str)
247 {
248         tbm_surface_info_s info;
249         char file[TDM_PATH_LEN];
250         int ret, bw, bh;
251
252         TDM_RETURN_IF_FAIL(buffer != NULL);
253         TDM_RETURN_IF_FAIL(str != NULL);
254
255         if (!dir)
256                 dir = ".";
257
258         ret = tbm_surface_get_info(buffer, &info);
259         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
260
261         tdm_helper_get_buffer_full_size(buffer, &bw, &bh);
262
263         snprintf(file, TDM_PATH_LEN, "%s/%c%c%c%c_%dx%d_%dx%d_%s",
264                          dir, FOURCC_STR(info.format), bw, bh, info.width, info.height, str);
265
266         tdm_helper_dump_buffer(buffer, file);
267 }
268 /* LCOV_EXCL_STOP */
269
270 EXTERN void
271 tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file)
272 {
273         char temp[TDM_PATH_LEN] = {0,};
274         tbm_surface_info_s info;
275         int len, ret;
276         const char *ext;
277         int bo_cnt;
278         int bw, bh;
279         char *dot, *p = temp;
280
281         TDM_RETURN_IF_FAIL(buffer != NULL);
282         TDM_RETURN_IF_FAIL(file != NULL);
283
284         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
285         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
286
287         if (IS_RGB(info.format))
288                 ext = file_exts[0];
289         else
290                 ext = file_exts[1];
291
292         dot = strrchr(file, '.');
293         if (!dot || strlen(dot + 1) != 3 || strncmp(dot + 1, ext, 3)) {
294                 len = strnlen(file, TDM_PATH_LEN - 5);
295                 strncat(p, file, len);
296                 p += len;
297                 *(p++) = '.';
298                 strncat(p, ext, 4);
299                 p += 3;
300                 *p = '\0';
301         } else {
302                 len = strnlen(file, TDM_PATH_LEN - 1);
303                 strncat(p, file, len);
304                 p += len;
305                 *p = '\0';
306         }
307
308         tdm_helper_get_buffer_full_size(buffer, &bw, &bh);
309
310         bo_cnt = tbm_surface_internal_get_num_bos(buffer);
311         TDM_DBG("buffer: bo_cnt(%d) %dx%d(%dx%d) %c%c%c%c, plane: (%p+%d, %d,%d) (%p+%d, %d,%d) (%p+%d, %d,%d)",
312                         bo_cnt, bw, bh, info.width, info.height, FOURCC_STR(info.format),
313                         info.planes[0].ptr, info.planes[0].offset, info.planes[0].stride, info.planes[0].size,
314                         info.planes[1].ptr, info.planes[1].offset, info.planes[1].stride, info.planes[1].size,
315                         info.planes[2].ptr, info.planes[2].offset, info.planes[2].stride, info.planes[2].size);
316
317         switch (info.format) {
318         case TBM_FORMAT_ARGB8888:
319         case TBM_FORMAT_XRGB8888:
320                 _tdm_helper_dump_png(temp, info.planes[0].ptr, bw, bh);
321                 break;
322         case TBM_FORMAT_YVU420:
323         case TBM_FORMAT_YUV420:
324                 _tdm_helper_dump_raw((const char*)temp,
325                                                          info.planes[0].ptr,
326                                                          info.planes[0].size,
327                                                          info.planes[1].ptr,
328                                                          info.planes[1].size,
329                                                          info.planes[2].ptr,
330                                                          info.planes[2].size);
331                 break;
332         case TBM_FORMAT_NV12:
333         case TBM_FORMAT_NV21:
334                 _tdm_helper_dump_raw((const char*)temp,
335                                                          info.planes[0].ptr,
336                                                          info.planes[0].size,
337                                                          info.planes[1].ptr,
338                                                          info.planes[1].size, NULL,
339                                                          0);
340                 break;
341         default:
342                 _tdm_helper_dump_raw((const char*)temp,
343                                                          info.planes[0].ptr,
344                                                          info.planes[0].size,
345                                                          info.planes[1].ptr,
346                                                          info.planes[1].size,
347                                                          info.planes[2].ptr,
348                                                          info.planes[2].size);
349                 break;
350         }
351
352         tbm_surface_unmap(buffer);
353
354         TDM_INFO("dump %s", temp);
355 }
356
357 EXTERN void
358 tdm_helper_clear_buffer_color(tbm_surface_h buffer, tdm_pos *pos, unsigned int color)
359 {
360         tbm_surface_info_s info;
361         int ret;
362
363         TDM_RETURN_IF_FAIL(buffer != NULL);
364
365         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
366         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
367
368         switch (info.format) {
369         case TBM_FORMAT_ARGB8888:
370         case TBM_FORMAT_XRGB8888:
371                 if (!pos) {
372                         memset(info.planes[0].ptr, 0, info.planes[0].stride * info.height);
373                 } else {
374                         unsigned char *p;
375                         int x, y;
376                         for (y = pos->y; y <= (pos->y + pos->h); y++) {
377                                 p = info.planes[0].ptr + info.planes[0].stride * y;
378                                 for (x = pos->x; x <= (pos->x + pos->w); x++) {
379                                         unsigned int *ibuf = (unsigned int*)p;
380                                         ibuf[x] = color;
381                                 }
382                         }
383                 }
384                 break;
385         case TBM_FORMAT_YVU420:
386         case TBM_FORMAT_YUV420:
387                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
388                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
389                 memset((char*)info.planes[2].ptr, 0x80, info.planes[2].stride * (info.height >> 1));
390                 break;
391         case TBM_FORMAT_NV12:
392         case TBM_FORMAT_NV21:
393                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
394                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
395                 break;
396         default:
397                 TDM_ERR("can't clear %c%c%c%c buffer", FOURCC_STR(info.format));
398                 break;
399         }
400
401         tbm_surface_unmap(buffer);
402 }
403
404 EXTERN void
405 tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos)
406 {
407         TDM_RETURN_IF_FAIL(buffer != NULL);
408
409         tdm_helper_clear_buffer_color(buffer, pos, 0);
410 }
411
412 EXTERN void
413 tdm_helper_clear_buffer(tbm_surface_h buffer)
414 {
415         TDM_RETURN_IF_FAIL(buffer != NULL);
416
417         tdm_helper_clear_buffer_pos(buffer, NULL);
418 }
419
420 EXTERN void
421 tdm_helper_get_buffer_full_size(tbm_surface_h buffer, int *buffer_w, int *buffer_h)
422 {
423         tbm_surface_info_s info;
424         int ret;
425
426         TDM_RETURN_IF_FAIL(buffer != NULL);
427
428         ret = tbm_surface_get_info(buffer, &info);
429         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
430
431         if (buffer_w) {
432                 if (IS_RGB(info.format))
433                         *buffer_w = info.planes[0].stride >> 2;
434                 else
435                         *buffer_w = info.planes[0].stride;
436         }
437
438         if (buffer_h)
439                 *buffer_h = info.planes[0].size / info.planes[0].stride;
440 }
441
442 static pixman_format_code_t
443 _tdm_helper_pixman_format_get(tbm_format format)
444 {
445         switch (format) {
446         case TBM_FORMAT_ARGB8888:
447                 return PIXMAN_a8r8g8b8;
448         case TBM_FORMAT_XRGB8888:
449                 return PIXMAN_x8r8g8b8;
450         default:
451                 return 0;
452         }
453
454         return 0;
455 }
456
457 EXTERN tdm_error
458 tdm_helper_convert_buffer(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
459                                                   tdm_pos *srcpos, tdm_pos *dstpos,
460                                                   tdm_transform transform, int over)
461 {
462         tbm_surface_info_s src_info, dst_info;
463         pixman_image_t *src_img = NULL, *dst_img = NULL;
464         pixman_format_code_t src_format, dst_format;
465         double scale_x, scale_y;
466         int rotate_step, bos;
467         pixman_transform_t t;
468         struct pixman_f_transform ft;
469         pixman_op_t op;
470         int src_stride, dst_stride;
471         int buf_width, err;
472         tdm_error ret = TDM_ERROR_OPERATION_FAILED;
473
474         TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
475         TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
476
477         bos = tbm_surface_internal_get_num_bos(srcbuf);
478         TDM_RETURN_VAL_IF_FAIL(bos == 1, TDM_ERROR_OPERATION_FAILED);
479
480         bos = tbm_surface_internal_get_num_bos(dstbuf);
481         TDM_RETURN_VAL_IF_FAIL(bos == 1, TDM_ERROR_OPERATION_FAILED);
482
483         err = tbm_surface_map(srcbuf, TBM_OPTION_READ, &src_info);
484         TDM_RETURN_VAL_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, TDM_ERROR_OPERATION_FAILED);
485
486         err = tbm_surface_map(dstbuf, TBM_OPTION_WRITE, &dst_info);
487         TDM_GOTO_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, unmap_srcbuf);
488
489         /* not handle buffers which have 2 more gem handles */
490         TDM_GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, unmap_dstbuf);
491         TDM_GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, unmap_dstbuf);
492
493         src_format = _tdm_helper_pixman_format_get(src_info.format);
494         TDM_GOTO_IF_FAIL(src_format > 0, unmap_dstbuf);
495         dst_format = _tdm_helper_pixman_format_get(dst_info.format);
496         TDM_GOTO_IF_FAIL(dst_format > 0, unmap_dstbuf);
497
498         buf_width = src_info.planes[0].stride >> 2;
499         src_stride = src_info.planes[0].stride;
500         src_img = pixman_image_create_bits(src_format, buf_width, src_info.height,
501                                                                            (uint32_t*)src_info.planes[0].ptr, src_stride);
502         TDM_GOTO_IF_FAIL(src_img, unref_img);
503
504         buf_width = dst_info.planes[0].stride >> 2;
505         dst_stride = dst_info.planes[0].stride;
506         dst_img = pixman_image_create_bits(dst_format, buf_width, dst_info.height,
507                                                                            (uint32_t*)dst_info.planes[0].ptr, dst_stride);
508         TDM_GOTO_IF_FAIL(dst_img, unref_img);
509
510         pixman_f_transform_init_identity(&ft);
511
512         if (transform & TDM_TRANSFORM_FLIPPED) {
513                 pixman_f_transform_scale(&ft, NULL, -1, 1);
514                 pixman_f_transform_translate(&ft, NULL, dstpos->w, 0);
515         }
516
517         rotate_step = transform & 0x3;
518         if (rotate_step > 0) {
519                 int c, s, tx = 0, ty = 0;
520                 switch (rotate_step) {
521                 case 1:
522                         c = 0, s = -1, tx = -dstpos->w;
523                         break;
524                 case 2:
525                         c = -1, s = 0, tx = -dstpos->w, ty = -dstpos->h;
526                         break;
527                 case 3:
528                         c = 0, s = 1, ty = -dstpos->h;
529                         break;
530                 }
531                 pixman_f_transform_translate(&ft, NULL, tx, ty);
532                 pixman_f_transform_rotate(&ft, NULL, c, s);
533         }
534
535         if (rotate_step % 2 == 0) {
536                 scale_x = (double)srcpos->w / dstpos->w;
537                 scale_y = (double)srcpos->h / dstpos->h;
538         } else {
539                 scale_x = (double)srcpos->w / dstpos->h;
540                 scale_y = (double)srcpos->h / dstpos->w;
541         }
542
543         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
544         pixman_f_transform_translate(&ft, NULL, srcpos->x, srcpos->y);
545         pixman_transform_from_pixman_f_transform(&t, &ft);
546         pixman_image_set_transform(src_img, &t);
547
548         op = (!over) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER;
549
550         pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0,
551                                                    dstpos->x, dstpos->y, dstpos->w, dstpos->h);
552
553         ret = TDM_ERROR_NONE;
554
555 unref_img:
556         if (src_img)
557                 pixman_image_unref(src_img);
558         if (dst_img)
559                 pixman_image_unref(dst_img);
560 unmap_dstbuf:
561         tbm_surface_unmap(dstbuf);
562 unmap_srcbuf:
563         tbm_surface_unmap(srcbuf);
564
565         return ret;
566 }
567
568 /* LCOV_EXCL_START */
569 EXTERN int
570 tdm_helper_get_fd(const char *env)
571 {
572         if (strncmp(env, "TBM_DRM_MASTER_FD", 17) && strncmp(env, "TDM_DRM_MASTER_FD", 17)) {
573                 TDM_INFO("DEPRECATED! '%s'", env);
574                 return -1;
575         }
576
577         return tbm_drm_helper_get_master_fd();
578 }
579
580 EXTERN void
581 tdm_helper_set_fd(const char *env, int fd)
582 {
583         if (strncmp(env, "TBM_DRM_MASTER_FD", 17) && strncmp(env, "TDM_DRM_MASTER_FD", 17)) {
584                 TDM_INFO("DEPRECATED! '%s'", env);
585                 return;
586         }
587
588         tbm_drm_helper_set_tbm_master_fd(fd);
589 }
590 /* LCOV_EXCL_STOP */
591
592 EXTERN void
593 tdm_helper_dump_start(char *dumppath, int *count)
594 {
595         if (dumppath == NULL || count == NULL) {
596                 TDM_DBG("tdm_helper_dump dumppath or count is null.");
597                 return;
598         }
599
600         tdm_dump_enable = 1;
601
602         TDM_DBG("tdm_helper_dump start.(path : %s)", dumppath);
603 }
604
605 EXTERN void
606 tdm_helper_dump_stop(void)
607 {
608         tdm_dump_enable = 0;
609
610         TDM_DBG("tdm_helper_dump stop.");
611 }
612
613 /* LCOV_EXCL_START */
614 static tdm_error
615 _tdm_helper_buffer_convert(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
616                                                    int dx, int dy, int dw, int dh, int count)
617 {
618         pixman_image_t *src_img = NULL, *dst_img = NULL;
619         pixman_format_code_t src_format, dst_format;
620         pixman_transform_t t;
621         struct pixman_f_transform ft;
622         pixman_op_t op;
623         tbm_surface_info_s src_info = {0, };
624         tbm_surface_info_s dst_info = {0, };
625         int stride, width;
626         double scale_x, scale_y;
627
628         TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
629         TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
630
631         if (tbm_surface_map(srcbuf, TBM_SURF_OPTION_READ, &src_info) != TBM_SURFACE_ERROR_NONE) {
632                 TDM_ERR("cannot mmap srcbuf\n");
633                 return TDM_ERROR_OPERATION_FAILED;
634         }
635
636         if (tbm_surface_map(dstbuf, TBM_SURF_OPTION_WRITE, &dst_info) != TBM_SURFACE_ERROR_NONE) {
637                 TDM_ERR("cannot mmap dstbuf\n");
638                 tbm_surface_unmap(srcbuf);
639                 return TDM_ERROR_OPERATION_FAILED;
640         }
641         TDM_GOTO_IF_FAIL(src_info.num_planes == 1, cant_convert);
642         TDM_GOTO_IF_FAIL(dst_info.num_planes == 1, cant_convert);
643
644         /* src */
645         src_format = _tdm_helper_pixman_format_get(src_info.format);
646         TDM_GOTO_IF_FAIL(src_format > 0, cant_convert);
647
648         width = src_info.planes[0].stride / 4;
649         stride = src_info.planes[0].stride;
650         src_img = pixman_image_create_bits(src_format, width, src_info.height,
651                                                                            (uint32_t*)src_info.planes[0].ptr, stride);
652         TDM_GOTO_IF_FAIL(src_img != NULL, cant_convert);
653
654         /* dst */
655         dst_format = _tdm_helper_pixman_format_get(dst_info.format);
656         TDM_GOTO_IF_FAIL(dst_format > 0, cant_convert);
657
658         width = dst_info.planes[0].stride / 4;
659         stride = dst_info.planes[0].stride;
660         dst_img = pixman_image_create_bits(dst_format, width, dst_info.height,
661                                                                            (uint32_t*)dst_info.planes[0].ptr, stride);
662         TDM_GOTO_IF_FAIL(dst_img != NULL, cant_convert);
663
664         pixman_f_transform_init_identity(&ft);
665
666         scale_x = (double)src_info.width / dw;
667         scale_y = (double)src_info.height / dh;
668
669         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
670         pixman_f_transform_translate(&ft, NULL, 0, 0);
671         pixman_transform_from_pixman_f_transform(&t, &ft);
672         pixman_image_set_transform(src_img, &t);
673
674         if (count == 0)
675                 op = PIXMAN_OP_SRC;
676         else
677                 op = PIXMAN_OP_OVER;
678
679         pixman_image_composite(op, src_img, NULL, dst_img,
680                                                    0, 0, 0, 0, dx, dy, dw, dh);
681
682         if (src_img)
683                 pixman_image_unref(src_img);
684         if (dst_img)
685                 pixman_image_unref(dst_img);
686
687         tbm_surface_unmap(srcbuf);
688         tbm_surface_unmap(dstbuf);
689
690         return TDM_ERROR_NONE;
691
692 cant_convert:
693         if (src_img)
694                 pixman_image_unref(src_img);
695
696         tbm_surface_unmap(srcbuf);
697         tbm_surface_unmap(dstbuf);
698
699         return TDM_ERROR_OPERATION_FAILED;
700 }
701 /* LCOV_EXCL_STOP */
702
703
704 EXTERN tdm_error
705 tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer,
706                                                   int x, int y, int w, int h,
707                                                   tdm_helper_capture_handler func, void *data)
708 {
709         tbm_surface_h surface;
710         tdm_error err;
711         int i, count, first = 0;
712
713         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
714         TDM_RETURN_VAL_IF_FAIL(dst_buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
715         TDM_RETURN_VAL_IF_FAIL(x >= 0, TDM_ERROR_INVALID_PARAMETER);
716         TDM_RETURN_VAL_IF_FAIL(y >= 0, TDM_ERROR_INVALID_PARAMETER);
717         TDM_RETURN_VAL_IF_FAIL(w >= 0, TDM_ERROR_INVALID_PARAMETER);
718         TDM_RETURN_VAL_IF_FAIL(h >= 0, TDM_ERROR_INVALID_PARAMETER);
719         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
720
721         err = tdm_output_get_layer_count(output, &count);
722         if (err != TDM_ERROR_NONE) {
723                 TDM_ERR("tdm_output_get_layer_count fail(%d)\n", err);
724                 return TDM_ERROR_OPERATION_FAILED;
725         }
726         if (count <= 0) {
727                 TDM_ERR("tdm_output_get_layer_count err(%d, %d)\n", err, count);
728                 return TDM_ERROR_BAD_MODULE;
729         }
730
731         for (i = count - 1; i >= 0; i--) {
732                 tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
733
734                 surface = tdm_layer_get_displaying_buffer(layer, &err);
735                 if (err != TDM_ERROR_NONE)
736                         continue;
737
738                 err = _tdm_helper_buffer_convert(surface, dst_buffer, x, y, w, h, first++);
739                 if (err != TDM_ERROR_NONE)
740                         TDM_DBG("convert fail %d-layer buffer\n", i);
741                 else
742                         TDM_DBG("convert success %d-layer buffer\n", i);
743         }
744
745         func(dst_buffer, data);
746
747         return TDM_ERROR_NONE;
748 }
749
750 static char *
751 _tdm_helper_get_backend_information(tdm_private_module *private_module, char *reply, int *len)
752 {
753         tdm_backend_module *module_data;
754         tdm_func_output *func_output;
755         tdm_func_layer *func_layer;
756         tdm_private_output *private_output = NULL;
757         tdm_private_layer *private_layer = NULL;
758         tdm_private_pp *private_pp = NULL;
759         tdm_private_capture *private_capture = NULL;
760         tdm_error ret;
761         int i;
762
763         func_output = &private_module->func_output;
764         func_layer = &private_module->func_layer;
765
766         /* module information */
767         module_data = private_module->module_data;
768         TDM_SNPRINTF(reply, len, "['%s' backend information]\n", module_data->name);
769         TDM_SNPRINTF(reply, len, "vendor: %s\n", module_data->vendor);
770         TDM_SNPRINTF(reply, len, "version: %d.%d\n\n",
771                                  (int)TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version),
772                                  (int)TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version));
773
774         /* output information */
775         TDM_SNPRINTF(reply, len, "['%s' backend output information]\n", module_data->name);
776         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
777         TDM_SNPRINTF(reply, len, "idx   maker   model   name   type   status   dpms   subpixel   align_w   min   max   phy(mm)\n");
778         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
779         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
780                 TDM_SNPRINTF(reply, len, "%d   %s   %s   %s   %s   %s   %s   %u   %d   %dx%d   %dx%d   %ux%u\n",
781                                          private_output->index, private_output->caps.maker,
782                                          private_output->caps.model, private_output->caps.name,
783                                          tdm_conn_str(private_output->caps.type),
784                                          tdm_status_str(private_output->caps.status),
785                                          tdm_dpms_str(private_output->current_dpms_value),
786                                          private_output->caps.subpixel,
787                                          TDM_FRONT_VALUE(private_output->caps.preferred_align),
788                                          TDM_FRONT_VALUE(private_output->caps.min_w),
789                                          TDM_FRONT_VALUE(private_output->caps.min_h),
790                                          TDM_FRONT_VALUE(private_output->caps.max_w),
791                                          TDM_FRONT_VALUE(private_output->caps.max_h),
792                                          private_output->caps.mmWidth, private_output->caps.mmHeight);
793
794                 TDM_SNPRINTF(reply, len, "\t%u modes:\n", private_output->caps.mode_count);
795
796                 if (private_output->caps.mode_count > 0) {
797                         TDM_SNPRINTF(reply, len, "\t\t name refresh (Hz) clk hdisp hss hse htot vdisp vss vse vtot vscan\n");
798                         for (i = 0; i < private_output->caps.mode_count; i++) {
799                                 char *current = (private_output->current_mode == private_output->caps.modes + i) ? "*" : " ";
800                                 TDM_SNPRINTF(reply, len, "\t\t%s%s %u %u %u %u %u %u %u %u %u %u %u ",
801                                                          current,
802                                                          private_output->caps.modes[i].name,
803                                                          private_output->caps.modes[i].vrefresh,
804                                                          private_output->caps.modes[i].clock,
805                                                          private_output->caps.modes[i].hdisplay,
806                                                          private_output->caps.modes[i].hsync_start,
807                                                          private_output->caps.modes[i].hsync_end,
808                                                          private_output->caps.modes[i].htotal,
809                                                          private_output->caps.modes[i].vdisplay,
810                                                          private_output->caps.modes[i].vsync_start,
811                                                          private_output->caps.modes[i].vsync_end,
812                                                          private_output->caps.modes[i].vtotal,
813                                                          private_output->caps.modes[i].vscan);
814                                 tdm_mode_flag_str(private_output->caps.modes[i].flags, &reply, len);
815                                 TDM_SNPRINTF(reply, len, " ");
816                                 tdm_mode_type_str(private_output->caps.modes[i].type, &reply, len);
817                                 TDM_SNPRINTF(reply, len, "\n");
818                         }
819                 }
820
821                 TDM_SNPRINTF(reply, len, "\t%d properties:\n", private_output->caps.prop_count);
822                 if (private_output->caps.prop_count > 0) {
823                         TDM_SNPRINTF(reply, len, "\t\tname\ttype\tidx\tvalue\n");
824                         for (i = 0; i < private_output->caps.prop_count; i++) {
825                                 tdm_value value;
826                                 TDM_DBG_RETURN_VAL_IF_FAIL(func_output->output_get_property, reply);
827                                 ret = func_output->output_get_property(private_output->output_backend,
828                                                                                                            private_output->caps.props[i].id,
829                                                                                                            &value);
830                                 TDM_DBG_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, reply);
831                                 TDM_SNPRINTF(reply, len, "\t\t%s\t%s\t%u\t",
832                                                          private_output->caps.props[i].name,
833                                                          tdm_value_type_str(private_output->caps.props[i].type),
834                                                          private_output->caps.props[i].id);
835                                 switch (private_output->caps.props[i].type) {
836                                 case TDM_VALUE_TYPE_PTR:
837                                         TDM_SNPRINTF(reply, len, "%p\n", value.ptr);
838                                         break;
839                                 case TDM_VALUE_TYPE_INT32:
840                                         TDM_SNPRINTF(reply, len, "%d\n", value.s32);
841                                         break;
842                                 case TDM_VALUE_TYPE_INT64:
843                                         TDM_SNPRINTF(reply, len, "%"PRId64"\n", value.s64);
844                                         break;
845                                 case TDM_VALUE_TYPE_UINT64:
846                                         TDM_SNPRINTF(reply, len, "%"PRIu64"\n", value.u64);
847                                         break;
848                                 case TDM_VALUE_TYPE_UINT32:
849                                 default:
850                                         TDM_SNPRINTF(reply, len, "%u\n", value.u32);
851                                         break;
852                                 }
853                         }
854                 }
855         }
856         if (LIST_IS_EMPTY(&private_module->output_list))
857                 TDM_SNPRINTF(reply, len, "(no output)\n");
858         TDM_SNPRINTF(reply, len, "\n");
859
860         /* layer information */
861         TDM_SNPRINTF(reply, len, "['%s' backend layer information]\n", module_data->name);
862         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
863         TDM_SNPRINTF(reply, len, "idx   output   zpos   buf   format   size   crop   geometry   transform\n");
864         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
865         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
866                 if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) {
867                         TDM_SNPRINTF(reply, len, "(no layer), hwc mode on\n");
868                         continue;
869                 }
870
871                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
872                         if (!private_layer->usable) {
873                                 tdm_info_layer info;
874                                 unsigned int format;
875                                 tdm_size size;
876                                 tbm_surface_info_s buf_info;
877
878                                 TDM_DBG_RETURN_VAL_IF_FAIL(func_layer->layer_get_info, reply);
879                                 memset(&info, 0, sizeof info);
880                                 ret = func_layer->layer_get_info(private_layer->layer_backend, &info);
881                                 TDM_DBG_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, reply);
882
883                                 if (!private_layer->showing_buffer)
884                                         continue;
885
886                                 format = tbm_surface_get_format(private_layer->showing_buffer->buffer);
887                                 tbm_surface_get_info(private_layer->showing_buffer->buffer, &buf_info);
888
889                                 size.h = tbm_surface_get_width(private_layer->showing_buffer->buffer);
890                                 size.v = tbm_surface_get_height(private_layer->showing_buffer->buffer);
891
892                                 if (info.src_config.format)
893                                         format = (info.src_config.format) ? : format;
894
895                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   %p   %c%c%c%c   %ux%u   %ux%u+%u+%u   %ux%u+%u+%u   %s\n",
896                                                          private_layer->index,
897                                                          private_output->index,
898                                                          private_layer->caps.zpos,
899                                                          private_layer->showing_buffer->buffer, FOURCC_STR(format), size.h, size.v,
900                                                          info.src_config.pos.w, info.src_config.pos.h, info.src_config.pos.x, info.src_config.pos.y,
901                                                          info.dst_pos.w, info.dst_pos.h, info.dst_pos.x, info.dst_pos.y,
902                                                          tdm_transform_str(info.transform));
903                         } else {
904                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   -\n",
905                                                          private_layer->index,
906                                                          private_output->index,
907                                                          private_layer->caps.zpos);
908                         }
909
910                         TDM_SNPRINTF(reply, len, "\tcaps\t: ");
911                         tdm_layer_caps_str(private_layer->caps.capabilities, &reply, len);
912                         TDM_SNPRINTF(reply, len, "\n");
913
914                         TDM_SNPRINTF(reply, len, "\tformats\t: ");
915                         if (private_layer->caps.format_count > 0) {
916                                 const char *sep = "";
917                                 for (i = 0; i < private_layer->caps.format_count; i++) {
918                                         if (private_layer->caps.formats[i] == 0)
919                                                 continue;
920                                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_layer->caps.formats[i]));
921                                         sep = ",";
922                                 }
923                                 TDM_SNPRINTF(reply, len, "\n");
924                         }
925
926                         TDM_SNPRINTF(reply, len, "\t%u properties:\n", private_layer->caps.prop_count);
927                         if (private_layer->caps.prop_count > 0) {
928                                 TDM_SNPRINTF(reply, len, "\t\tname\ttype\tidx\tvalue\n");
929                                 for (i = 0; i < private_layer->caps.prop_count; i++) {
930                                         tdm_value value;
931                                         TDM_DBG_RETURN_VAL_IF_FAIL(func_layer->layer_get_property, reply);
932                                         ret = func_layer->layer_get_property(private_layer->layer_backend,
933                                                                                                                  private_layer->caps.props[i].id,
934                                                                                                                  &value);
935                                         TDM_DBG_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, reply);
936                                         TDM_SNPRINTF(reply, len, "\t\t%s\t%s\t%u\t",
937                                                                  private_layer->caps.props[i].name,
938                                                                  tdm_value_type_str(private_output->caps.props[i].type),
939                                                                  private_layer->caps.props[i].id);
940                                 switch (private_layer->caps.props[i].type) {
941                                 case TDM_VALUE_TYPE_PTR:
942                                         TDM_SNPRINTF(reply, len, "%p\n", value.ptr);
943                                         break;
944                                 case TDM_VALUE_TYPE_INT32:
945                                         TDM_SNPRINTF(reply, len, "%d\n", value.s32);
946                                         break;
947                                 case TDM_VALUE_TYPE_INT64:
948                                         TDM_SNPRINTF(reply, len, "%"PRId64"\n", value.s64);
949                                         break;
950                                 case TDM_VALUE_TYPE_UINT64:
951                                         TDM_SNPRINTF(reply, len, "%"PRIu64"\n", value.u64);
952                                         break;
953                                 case TDM_VALUE_TYPE_UINT32:
954                                 default:
955                                         TDM_SNPRINTF(reply, len, "%u\n", value.u32);
956                                         break;
957                                 }
958                                 }
959                         }
960                 }
961         }
962         if (LIST_IS_EMPTY(&private_module->output_list))
963                 TDM_SNPRINTF(reply, len, "(no layer)\n");
964         TDM_SNPRINTF(reply, len, "\n");
965
966         if (private_module->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
967                 const char *sep = "";
968                 TDM_SNPRINTF(reply, len, "['%s' backend PP information]\n", module_data->name);
969                 TDM_SNPRINTF(reply, len, "caps\t: ");
970                 tdm_pp_caps_str(private_module->caps_pp.capabilities, &reply, len);
971                 TDM_SNPRINTF(reply, len, "\n");
972                 TDM_SNPRINTF(reply, len, "formats\t: ");
973                 for (i = 0; i < private_module->caps_pp.format_count; i++) {
974                         if (private_module->caps_pp.formats[i] == 0)
975                                 continue;
976                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_module->caps_pp.formats[i]));
977                         sep = ",";
978                 }
979                 TDM_SNPRINTF(reply, len, "\n");
980                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
981                                          TDM_FRONT_VALUE(private_module->caps_pp.min_w),
982                                          TDM_FRONT_VALUE(private_module->caps_pp.min_h),
983                                          TDM_FRONT_VALUE(private_module->caps_pp.max_w),
984                                          TDM_FRONT_VALUE(private_module->caps_pp.max_h),
985                                          TDM_FRONT_VALUE(private_module->caps_pp.preferred_align));
986                 if (!LIST_IS_EMPTY(&private_module->pp_list)) {
987                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
988                         TDM_SNPRINTF(reply, len, "src(format size crop)  |  dst(format size crop)  |  transform\n");
989                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
990                         LIST_FOR_EACH_ENTRY(private_pp, &private_module->pp_list, link) {
991                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %ux%u %ux%u+%u+%u | %c%c%c%c %ux%u %ux%u+%u+%u | %s\n",
992                                                          FOURCC_STR(private_pp->info.src_config.format),
993                                                          private_pp->info.src_config.size.h,
994                                                          private_pp->info.src_config.size.v,
995                                                          private_pp->info.src_config.pos.x, private_pp->info.src_config.pos.y,
996                                                          private_pp->info.src_config.pos.w, private_pp->info.src_config.pos.h,
997                                                          FOURCC_STR(private_pp->info.dst_config.format),
998                                                          private_pp->info.dst_config.size.h,
999                                                          private_pp->info.dst_config.size.v,
1000                                                          private_pp->info.dst_config.pos.x, private_pp->info.dst_config.pos.y,
1001                                                          private_pp->info.dst_config.pos.w, private_pp->info.dst_config.pos.h,
1002                                                          tdm_transform_str(private_pp->info.transform));
1003                         }
1004                 }
1005         } else {
1006                 TDM_SNPRINTF(reply, len, "['%s' backend No PP capability]\n", module_data->name);
1007         }
1008         TDM_SNPRINTF(reply, len, "\n");
1009
1010         if (private_module->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
1011                 const char *sep = "";
1012                 TDM_SNPRINTF(reply, len, "['%s' backend capture information]\n", module_data->name);
1013                 TDM_SNPRINTF(reply, len, "caps\t: ");
1014                 tdm_capture_caps_str(private_module->caps_capture.capabilities, &reply, len);
1015                 TDM_SNPRINTF(reply, len, "\n");
1016                 TDM_SNPRINTF(reply, len, "formats\t: ");
1017                 for (i = 0; i < private_module->caps_capture.format_count; i++) {
1018                         if (private_module->caps_capture.formats[i] == 0)
1019                                 continue;
1020                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_module->caps_capture.formats[i]));
1021                         sep = ",";
1022                 }
1023                 TDM_SNPRINTF(reply, len, "\n");
1024                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
1025                                          TDM_FRONT_VALUE(private_module->caps_capture.min_w),
1026                                          TDM_FRONT_VALUE(private_module->caps_capture.min_h),
1027                                          TDM_FRONT_VALUE(private_module->caps_capture.max_w),
1028                                          TDM_FRONT_VALUE(private_module->caps_capture.max_h),
1029                                          TDM_FRONT_VALUE(private_module->caps_capture.preferred_align));
1030                 if (!LIST_IS_EMPTY(&private_module->capture_list)) {
1031                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
1032                         TDM_SNPRINTF(reply, len, "dst(format size crop)  |  transform\n");
1033                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
1034                         LIST_FOR_EACH_ENTRY(private_capture, &private_module->capture_list, link) {
1035                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %ux%u %ux%u+%u+%u | %s\n",
1036                                                          FOURCC_STR(private_capture->info.dst_config.format),
1037                                                          private_capture->info.dst_config.size.h,
1038                                                          private_capture->info.dst_config.size.v,
1039                                                          private_capture->info.dst_config.pos.x, private_capture->info.dst_config.pos.y,
1040                                                          private_capture->info.dst_config.pos.w, private_capture->info.dst_config.pos.h,
1041                                                          tdm_transform_str(private_capture->info.transform));
1042                         }
1043                 }
1044         } else {
1045                 TDM_SNPRINTF(reply, len, "['%s' backend No Capture capability]\n", module_data->name);
1046         }
1047         TDM_SNPRINTF(reply, len, "\n");
1048         return reply;
1049 }
1050
1051 EXTERN void
1052 tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len)
1053 {
1054         tdm_private_display *private_display;
1055         tdm_private_module *private_module = NULL;
1056
1057         TDM_DBG_RETURN_IF_FAIL(dpy != NULL);
1058
1059         private_display = dpy;
1060
1061         _pthread_mutex_lock(&private_display->lock);
1062
1063         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
1064                 reply = _tdm_helper_get_backend_information(private_module, reply, len);
1065         }
1066
1067         _pthread_mutex_unlock(&private_display->lock);
1068 }
1069
1070 /* LCOV_EXCL_START */
1071 EXTERN int
1072 tdm_helper_commit_per_vblank_enabled(tdm_display *dpy)
1073 {
1074         TDM_DEPRECATED("Use tdm_helper_output_commit_per_vblank_enabled");
1075
1076         return 0;
1077 }
1078 /* LCOV_EXCL_STOP */
1079
1080 EXTERN int
1081 tdm_helper_output_commit_per_vblank_enabled(tdm_output *output)
1082 {
1083         tdm_private_output *private_output = output;
1084
1085         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, -1);
1086
1087         return !!private_output->commit_per_vblank;
1088 }
1089
1090 EXTERN unsigned int
1091 tdm_helper_output_vblank_timer_expired(tdm_output *output)
1092 {
1093         tdm_private_output *private_output = output;
1094
1095         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, -1);
1096
1097         return private_output->vblank_timeout_timer_expired;
1098 }