psb_texture.c revision 0ff300115fba4b587b9a930440c6f08812877b7a
1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 * Copyright (c) Imagination Technologies Limited, UK
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 PRECISION INSIGHT 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 * Authors:
26 *    Binglin Chen <binglin.chen@intel.com>
27 *    Zhaohan Ren  <zhaohan.ren@intel.com>
28 *    Shengquan Yuan  <shengquan.yuan@intel.com>
29  */
30
31#include <stdio.h>
32#include <unistd.h>
33#include <math.h>
34
35#ifdef ANDROID
36#include <linux/psb_drm.h>
37#else
38#include <psb_drm.h>
39#endif
40
41#include <va/va_backend.h>
42#include <va/va_dricommon.h>
43#include "psb_drv_debug.h"
44
45#include <wsbm/wsbm_manager.h>
46
47#ifndef ANDROID
48#include <X11/Xlib.h>
49#include "x11/psb_xrandr.h"
50#include "x11/psb_x11.h"
51#endif
52
53#include "pvr2d.h"
54
55#include "psb_drv_video.h"
56#include "psb_output.h"
57#include "psb_surface_ext.h"
58
59#include "psb_texture.h"
60
61#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
62#define INIT_OUTPUT_PRIV    psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
63#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
64#define SUBPIC(id)  ((object_subpic_p) object_heap_lookup( &driver_data->subpic_heap, id ))
65
66#define Degree (2*PI / 360.0)
67#define PI 3.1415927
68
69#define OV_HUE_DEFAULT_VALUE   0
70#define OV_HUE_MIN            -30
71#define OV_HUE_MAX             30
72
73#define OV_BRIGHTNESS_DEFAULT_VALUE   0
74#define OV_BRIGHTNESS_MIN            -50
75#define OV_BRIGHTNESS_MAX             50
76
77#define OV_CONTRAST_DEFAULT_VALUE     0
78#define OV_CONTRAST_MIN              -100
79#define OV_CONTRAST_MAX               100
80
81#define OV_SATURATION_DEFAULT_VALUE   100
82#define OV_SATURATION_MIN             0
83#define OV_SATURATION_MAX             200
84
85typedef struct _psb_transform_coeffs_ {
86    double rY, rCb, rCr;
87    double gY, gCb, gCr;
88    double bY, bCb, bCr;
89} psb_transform_coeffs;
90
91typedef enum _psb_videotransfermatrix {
92    PSB_VideoTransferMatrixMask = 0x07,
93    PSB_VideoTransferMatrix_Unknown = 0,
94    PSB_VideoTransferMatrix_BT709 = 1,
95    PSB_VideoTransferMatrix_BT601 = 2,
96    PSB_VideoTransferMatrix_SMPTE240M = 3
97} psb_videotransfermatrix;
98
99typedef enum _psb_nominalrange {
100    PSB_NominalRangeMask = 0x07,
101    PSB_NominalRange_Unknown = 0,
102    PSB_NominalRange_Normal = 1,
103    PSB_NominalRange_Wide = 2,
104    /* explicit range forms */
105    PSB_NominalRange_0_255 = 1,
106    PSB_NominalRange_16_235 = 2,
107    PSB_NominalRange_48_208 = 3
108} psb_nominalrange;
109
110/*
111 * ITU-R BT.601, BT.709 and SMPTE 240M transfer matrices from VA 2.0
112 * Video Color Field definitions Design Spec(Version 0.03).
113 * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1]
114 * and [Pb, Pr] components are in the range [-0.5, 0.5].
115 */
116static psb_transform_coeffs s601 = {
117    1, -0.000001, 1.402,
118    1, -0.344136, -0.714136,
119    1, 1.772, 0
120};
121
122static psb_transform_coeffs s709 = {
123    1, 0, 1.5748,
124    1, -0.187324, -0.468124,
125    1, 1.8556, 0
126};
127
128static psb_transform_coeffs s240M = {
129    1, -0.000657, 1.575848,
130    1, -0.226418, -0.476529,
131    1, 1.825958, 0.000378
132};
133
134static void psb_setup_coeffs(struct psb_texture_s * pPriv);
135static void psb_scale_transfermatrix(psb_transform_coeffs * transfer_matrix,
136                                     double YColumScale, double CbColumScale,
137                                     double CrColumnScale);
138static void psb_select_transfermatrix(struct psb_texture_s * pPriv,
139                                      psb_transform_coeffs * transfer_matrix,
140                                      double *Y_offset, double *CbCr_offset,
141                                      double *RGB_offset);
142static void psb_create_coeffs(double yOff, double uOff, double vOff, double rgbOff,
143                              double yScale, double uScale, double vScale,
144                              double brightness, double contrast,
145                              double *pYCoeff, double *pUCoeff, double *pVCoeff,
146                              double *pConstant);
147static void psb_convert_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
148                               double ConstantTerm, signed char *pY, signed char *pU,
149                               signed char *pV, signed short *constant,
150                               unsigned char *pShift);
151static int psb_check_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
152                            double ConstantTerm, signed char byShift);
153static void
154psb_transform_sathuecoeffs(psb_transform_coeffs * dest,
155                           const psb_transform_coeffs * const source,
156                           double fHue, double fSat);
157
158static unsigned long PVRCalculateStride(unsigned long widthInPixels, unsigned int bitsPerPixel, unsigned int stride_alignment)
159{
160    int ulActiveLinelenInPixels = (widthInPixels + (stride_alignment - 1)) & ~(stride_alignment - 1);
161    return ((ulActiveLinelenInPixels * bitsPerPixel) + 7) >> 3;
162}
163
164static int pvr_context_create(unsigned char **pvr_ctx)
165{
166#ifdef _FOR_FPGA_
167    return PVR2D_OK;
168#endif
169    int ret = 0;
170    int pvr_devices = PVR2DEnumerateDevices(0);
171    PVR2DDEVICEINFO *pvr_devs = NULL;
172
173    if ((pvr_devices < PVR2D_OK) || (pvr_devices == 0)) {
174        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s(): PowerVR device not found", __func__);
175        goto out;
176    }
177
178    pvr_devs = calloc(1, pvr_devices * sizeof(*pvr_devs));
179    if (!pvr_devs) {
180        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s(): not enough memory", __func__);
181        goto out;
182    }
183
184    ret = PVR2DEnumerateDevices(pvr_devs);
185    if (ret != PVR2D_OK) {
186        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s(): PVR2DEnumerateDevices() failed(%d)", __func__,
187                           ret);
188        goto out;
189    }
190
191    /* Choose the first display device */
192    ret = PVR2DCreateDeviceContext(pvr_devs[0].ulDevID, (PVR2DCONTEXTHANDLE *)pvr_ctx, 0);
193    if (ret != PVR2D_OK) {
194        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s(): PVR2DCreateDeviceContext() failed(%d)", __func__,
195                           ret);
196        goto out;
197    }
198
199out:
200    if (pvr_devs)
201        free(pvr_devs);
202
203    return ret;
204}
205
206void psb_fix_drmfd_closesequence(psb_driver_data_p driver_data)
207{
208    driver_data->dup_drm_fd = dup(driver_data->drm_fd);
209}
210
211
212int psb_ctexture_init(VADriverContextP ctx)
213{
214    INIT_DRIVER_DATA;
215
216    struct psb_texture_s *texture_priv = &driver_data->ctexture_priv;
217    int i, ret;
218
219    ret = pvr_context_create(&driver_data->hPVR2DContext);
220    if (ret != PVR2D_OK) {
221        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s(): null PVR context!!", __func__);
222        return ret;
223    }
224
225    texture_priv->video_transfermatrix = PSB_VideoTransferMatrix_BT709;
226    texture_priv->src_nominalrange = PSB_NominalRange_0_255;
227    texture_priv->dst_nominalrange = PSB_NominalRange_0_255;
228
229    texture_priv->brightness.Value = OV_BRIGHTNESS_DEFAULT_VALUE;
230    texture_priv->brightness.Fraction = 0;
231    texture_priv->contrast.Value = OV_CONTRAST_DEFAULT_VALUE;
232    texture_priv->contrast.Fraction = 0;
233    texture_priv->hue.Value = OV_HUE_DEFAULT_VALUE;
234    texture_priv->hue.Fraction = 0;
235    texture_priv->saturation.Value = OV_SATURATION_DEFAULT_VALUE;
236    texture_priv->saturation.Fraction = 0;
237
238    texture_priv->gamma5 = 0xc0c0c0;
239    texture_priv->gamma4 = 0x808080;
240    texture_priv->gamma3 = 0x404040;
241    texture_priv->gamma2 = 0x202020;
242    texture_priv->gamma1 = 0x101010;
243    texture_priv->gamma0 = 0x080808;
244
245    texture_priv->dri_init_flag = 0;
246    texture_priv->drawable_update_flag = 0;
247    texture_priv->extend_dri_init_flag = 0;
248    texture_priv->current_blt_buffer = 0;
249    texture_priv->extend_current_blt_buffer = 0;
250    texture_priv->adjust_window_flag = 0;
251    texture_priv->destw_save = 0;
252    texture_priv->desth_save = 0;
253    texture_priv->local_rotation_save = -1;
254    texture_priv->extend_rotation_save = -1;
255    texture_priv->dri_drawable = NULL;
256    texture_priv->extend_dri_drawable = NULL;
257
258    for (i = 0; i < DRI2_BLIT_BUFFERS_NUM; i++) {
259        texture_priv->blt_meminfo[i] = NULL;
260        texture_priv->extend_blt_meminfo[i] = NULL;
261    }
262
263    for (i = 0; i < DRI2_FLIP_BUFFERS_NUM; i++)
264        texture_priv->flip_meminfo[i] = NULL;
265
266    texture_priv->blt_meminfo_pixmap = NULL;
267
268    for (i = 0; i < 6; i++)
269        texture_priv->pal_meminfo[i] = NULL;
270
271    psb_setup_coeffs(texture_priv);
272    psb_fix_drmfd_closesequence(driver_data);
273
274    return 0;
275}
276
277void psb_ctexture_deinit(VADriverContextP ctx)
278{
279    INIT_DRIVER_DATA;
280    PVR2DERROR ePVR2DStatus;
281    int i;
282
283    struct psb_texture_s *texture_priv = &driver_data->ctexture_priv;
284
285    if (texture_priv->blt_meminfo_pixmap) {
286        ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, texture_priv->blt_meminfo_pixmap);
287        if (ePVR2DStatus != PVR2D_OK)
288            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
289    }
290
291    for (i = 0; i < DRI2_BLIT_BUFFERS_NUM; i++) {
292        if (texture_priv->blt_meminfo[i]) {
293            ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, texture_priv->blt_meminfo[i]);
294            if (ePVR2DStatus != PVR2D_OK)
295                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
296            texture_priv->blt_meminfo[i] = NULL;
297        }
298    }
299
300    for (i = 0; i < DRI2_FLIP_BUFFERS_NUM; i++) {
301        if (texture_priv->flip_meminfo[i]) {
302            ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, texture_priv->flip_meminfo[i]);
303            if (ePVR2DStatus != PVR2D_OK)
304                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
305            texture_priv->flip_meminfo[i] = NULL;
306        }
307    }
308
309    for (i = 0; i < DRI2_BLIT_BUFFERS_NUM; i++) {
310        if (texture_priv->extend_blt_meminfo[i]) {
311            ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, texture_priv->extend_blt_meminfo[i]);
312            if (ePVR2DStatus != PVR2D_OK)
313                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
314            texture_priv->extend_blt_meminfo[i] = NULL;
315        }
316    }
317
318
319    for (i = 0; i < 6; i++) {
320        if (texture_priv->pal_meminfo[i]) {
321            ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, texture_priv->pal_meminfo[i]);
322            if (ePVR2DStatus != PVR2D_OK)
323                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
324            texture_priv->pal_meminfo[i] = NULL;
325        }
326    }
327
328    if (driver_data->hPVR2DContext) {
329        ePVR2DStatus = PVR2DDestroyDeviceContext(driver_data->hPVR2DContext);
330        if (ePVR2DStatus != PVR2D_OK)
331            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
332        driver_data->hPVR2DContext = NULL;
333    }
334
335    if (driver_data->dup_drm_fd)
336        close(driver_data->dup_drm_fd);
337}
338
339/* calculate subpicture size according to the downscale situation of both main and subpicture bitstream */
340static void psb_calculate_subpic_size(int surf_width, int surf_height, int dst_w, int dst_h, PsbVASurfaceRec *surface_subpic)
341{
342    float src_h_ratio, src_v_ratio;
343    float subpic_h_ratio, subpic_v_ratio;
344    float subpic_h_dest_ratio, subpic_v_dest_ratio;
345
346    src_h_ratio = (float)surf_width / dst_w;
347    src_v_ratio = (float)surf_height / dst_h;
348
349    subpic_h_ratio = (float)surface_subpic->subpic_srcw / surface_subpic->subpic_dstw;
350    subpic_v_ratio = (float)surface_subpic->subpic_srch / surface_subpic->subpic_dsth;
351
352    subpic_h_dest_ratio = (float)dst_w / surface_subpic->subpic_dstw;
353    subpic_v_dest_ratio = (float)dst_h / surface_subpic->subpic_dsth;
354
355    if (!(surface_subpic->subpic_flags & VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD)) {
356        /* If coordinates are video relative then scale subpicture with video */
357        surface_subpic->subpic_dstx /= src_h_ratio;
358        surface_subpic->subpic_dsty /= src_v_ratio;
359        surface_subpic->subpic_dstx /= subpic_h_ratio;
360        surface_subpic->subpic_dsty /= subpic_v_ratio;
361
362        surface_subpic->subpic_dstw /= src_h_ratio;
363        surface_subpic->subpic_dsth /= src_v_ratio;
364        surface_subpic->subpic_dstw /= subpic_h_ratio;
365        surface_subpic->subpic_dsth /= subpic_v_ratio;
366    }
367}
368
369static PPVR2DMEMINFO psb_check_subpic_buffer(psb_driver_data_p driver_data, PsbVASurfaceRec* surface_subpic)
370{
371    unsigned int i, j;
372    unsigned char* tmp_buffer;
373    unsigned char tmp;
374    PVR2DERROR ePVR2DStatus;
375
376    /* Find and return the wrapped buffer index */
377    for (i = 0; i < VIDEO_BUFFER_NUM; i++) {
378        if (driver_data->wrapped_subpic_id[i] == surface_subpic->subpic_id && driver_data->subpicBuf[i]) {
379            return driver_data->subpicBuf[i];
380        }
381    }
382
383    /* Wrap a un-wrapped buffer and return */
384    for (i = 0; i < VIDEO_BUFFER_NUM; i++) {
385        if (driver_data->wrapped_subpic_id[i] == VA_INVALID_ID) {
386            tmp_buffer = NULL;
387            tmp_buffer = wsbmBOMap(surface_subpic->bo, WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
388            if (NULL == tmp_buffer) {
389                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d: wsbmBOMap failed!",
390                        __FUNCTION__, __LINE__);
391                return NULL;
392            }
393            for (j = 0; j < surface_subpic->size; j = j + 4096) {
394                tmp = *(tmp_buffer + j);
395                if (tmp == 0)
396                    *(tmp_buffer + j) = 0;
397            }
398
399            ePVR2DStatus = PVR2DMemWrap(driver_data->hPVR2DContext,
400                                        tmp_buffer,
401                                        0,
402                                        surface_subpic->size,
403                                        NULL,
404                                        &driver_data->subpicBuf[i]);
405            if (ePVR2DStatus != PVR2D_OK) {
406                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemWrap error %d\n", __FUNCTION__, ePVR2DStatus);
407                return NULL;
408            }
409
410            driver_data->wrapped_subpic_id[i] = surface_subpic->subpic_id;
411            return driver_data->subpicBuf[i];
412        }
413    }
414
415    if (i == VIDEO_BUFFER_NUM - 1) {
416        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Out of warpped subpic buffer memory\n", __FUNCTION__);
417        return NULL;
418    }
419
420    return NULL;
421}
422
423
424void psb_init_surface_pvr2dbuf(psb_driver_data_p driver_data)
425{
426    int i;
427    for (i = 0; i < VIDEO_BUFFER_NUM; i++) {
428        driver_data->videoBuf[i] = NULL;
429        driver_data->subpicBuf[i] = NULL;
430        driver_data->wrapped_surface_id[i] = VA_INVALID_ID;
431        driver_data->wrapped_subpic_id[i] = VA_INVALID_ID;
432    }
433
434}
435
436void psb_free_surface_pvr2dbuf(psb_driver_data_p driver_data)
437{
438    int i;
439    PVR2DERROR ePVR2DStatus;
440
441    for (i = 0; i < VIDEO_BUFFER_NUM; i++) {
442        if ((driver_data->wrapped_surface_id[i] != VA_INVALID_ID) && driver_data->videoBuf[i]) {
443            ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, driver_data->videoBuf[i]);
444            if (ePVR2DStatus != PVR2D_OK)
445                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
446        }
447
448        if ((driver_data->wrapped_subpic_id[i] != VA_INVALID_ID) && driver_data->subpicBuf[i]) {
449            ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, driver_data->subpicBuf[i]);
450            if (ePVR2DStatus != PVR2D_OK)
451                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
452        }
453
454        driver_data->wrapped_surface_id[i] = VA_INVALID_ID;
455        driver_data->wrapped_subpic_id[i] = -1;
456
457        driver_data->videoBuf[i] = NULL;
458        driver_data->subpicBuf[i] = NULL;
459    }
460}
461
462
463static PPVR2DMEMINFO psb_wrap_surface_pvr2dbuf(psb_driver_data_p driver_data, VASurfaceID surface)
464{
465    int i, j;
466    unsigned char* tmp_buffer;
467    unsigned char tmp;
468    object_surface_p obj_surface = SURFACE(surface);
469    psb_surface_p psb_surface;
470    VAStatus vaStatus = VA_STATUS_SUCCESS;
471    PVR2DERROR ePVR2DStatus;
472
473    CHECK_SURFACE(obj_surface);
474    psb_surface = obj_surface->psb_surface;
475
476    /* Find and return the wrapped buffer index */
477    for (i = 0; i < VIDEO_BUFFER_NUM; i++) {
478        if (driver_data->wrapped_surface_id[i] == surface && driver_data->videoBuf[i]) {
479            return driver_data->videoBuf[i];
480        }
481    }
482
483    /* Wrap a un-wrapped buffer and return */
484    for (i = 0; i < VIDEO_BUFFER_NUM; i++) {
485        if (driver_data->wrapped_surface_id[i] == VA_INVALID_ID) {
486            tmp_buffer = NULL;
487            tmp_buffer = wsbmBOMap(psb_surface->buf.drm_buf, WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
488            if (NULL == tmp_buffer) {
489                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d: wsbmBOMap failed!",
490                        __FUNCTION__, __LINE__);
491                return NULL;
492            }
493            for (j = 0; j < psb_surface->size; j = j + 4096) {
494                tmp = *(tmp_buffer + j);
495                if (tmp == 0)
496                    *(tmp_buffer + j) = 0;
497            }
498
499            ePVR2DStatus = PVR2DMemWrap(driver_data->hPVR2DContext,
500                                        tmp_buffer,
501                                        0,
502                                        psb_surface->size,
503                                        NULL,
504                                        &driver_data->videoBuf[i]);
505            if (ePVR2DStatus != PVR2D_OK) {
506                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemWrap error %d\n", __FUNCTION__, ePVR2DStatus);
507            }
508
509            driver_data->wrapped_surface_id[i] = surface;
510            return driver_data->videoBuf[i];
511        }
512    }
513
514    if (i == VIDEO_BUFFER_NUM - 1) {
515        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Out of warpped buffer memory\n", __FUNCTION__);
516        return NULL;
517    }
518
519    return NULL;
520}
521
522void psb_putsurface_textureblit(
523    VADriverContextP ctx, unsigned char *dst, VASurfaceID surface, int src_x, int src_y, int src_w,
524    int src_h, int dst_x, int dst_y, int dst_w, int dst_h, unsigned int subtitle,
525    int width, int height,
526    int src_pitch, struct _WsbmBufferObject * src_buf,
527    unsigned int placement, int wrap_dst)
528{
529    INIT_DRIVER_DATA;
530    unsigned int i;
531    unsigned char *tmp_palette;
532    struct psb_texture_s *texture_priv = &driver_data->ctexture_priv;
533    object_surface_p obj_surface;
534    PsbVASurfaceRec *surface_subpic = NULL;
535    VAStatus vaStatus = VA_STATUS_SUCCESS;
536    obj_surface = SURFACE(surface);
537
538    PVR2D_VPBLT sBltVP;
539    PVR2DERROR ePVR2DStatus;
540    PPVR2DMEMINFO pVaVideoSubpicMemInfo;
541    PPVR2DMEMINFO pVaVideoMemInfo;
542    PPVR2DMEMINFO pDstMeminfo;
543
544    src_pitch = (src_pitch + 0x3) & ~0x3;
545
546    if (NULL == obj_surface) {
547        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Invalid surface ID 0x%08x!\n", __func__, surface);
548        return;
549    }
550    surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
551    /* check whether we need to update coeffs */
552    if ((height > 576) &&
553        (texture_priv->video_transfermatrix != PSB_VideoTransferMatrix_BT709)) {
554        texture_priv->video_transfermatrix = PSB_VideoTransferMatrix_BT709;
555        texture_priv->update_coeffs = 1;
556    } else if ((height <= 576) &&
557               (texture_priv->video_transfermatrix != PSB_VideoTransferMatrix_BT601)) {
558        texture_priv->video_transfermatrix = PSB_VideoTransferMatrix_BT601;
559        texture_priv->update_coeffs = 1;
560    }
561
562    /* prepare coeffs if needed */
563    memset(&sBltVP, 0, sizeof(PVR2D_VPBLT));
564    if (texture_priv->update_coeffs == 1) {
565        psb_setup_coeffs(texture_priv);
566        sBltVP.psYUVCoeffs = (PPVR2D_YUVCOEFFS) & texture_priv->coeffs;
567        /* FIXME: is it right? */
568        sBltVP.bCoeffsGiven  = 1;
569    }
570
571    pVaVideoMemInfo = psb_wrap_surface_pvr2dbuf(driver_data, surface);
572    if (!pVaVideoMemInfo) {
573        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get source PVR2DMEMINFO!\n", __func__);
574        return;
575    }
576
577    /* wrap the dest source */
578    /* FIXME: this is wrap for rgb565 */
579    if (wrap_dst == 0) {
580
581        pDstMeminfo = (PPVR2DMEMINFO)dst;
582        if (IS_MFLD(driver_data))
583            sBltVP.sDst.Stride = PVRCalculateStride(((struct dri_drawable*)texture_priv->dri_drawable)->width, 32, 8);
584        sBltVP.sDst.Format = PVR2D_ARGB8888;
585
586    } else {
587        ePVR2DStatus = PVR2DMemWrap(driver_data->hPVR2DContext,
588                                    dst,
589                                    0,
590                                    (dst_w * dst_h * 2),
591                                    NULL,
592                                    &pDstMeminfo);
593        if (ePVR2DStatus != PVR2D_OK) {
594            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemWrap error %d\n", __FUNCTION__, ePVR2DStatus);
595            return;
596        }
597
598        /* FIXME: this wrong, how to get system pitch */
599        sBltVP.sDst.Stride = dst_w * 2;//align_to(dst_w, 64);
600        sBltVP.sDst.Format = PVR2D_RGB565;
601    }
602    sBltVP.sDst.pSurfMemInfo = pDstMeminfo;
603    sBltVP.sDst.SurfOffset   = 0;
604    sBltVP.sDst.SurfWidth = dst_w;
605    sBltVP.sDst.SurfHeight = dst_h;
606
607    /* Y plane UV plane */
608    sBltVP.uiNumLayers = 1;
609    sBltVP.sSrc->Stride = src_pitch;
610    sBltVP.sSrc->Format = VA_FOURCC_NV12;
611    sBltVP.sSrc->SurfWidth = width;
612    sBltVP.sSrc->SurfHeight = height;
613    sBltVP.sSrc[0].pSurfMemInfo = pVaVideoMemInfo;
614
615    /* FIXME: check for top-bottom */
616    sBltVP.sSrc->SurfOffset = 0;
617
618    /* FIXME: check rotation setting */
619    /* FIXME: use PVR define */
620    sBltVP.RotationValue = 1;
621
622    /* clip box */
623    sBltVP.rcDest.left = dst_x;
624    sBltVP.rcDest.right = dst_x + dst_w;
625    sBltVP.rcDest.top = dst_y;
626    sBltVP.rcDest.bottom = dst_y + dst_h;
627
628    sBltVP.rcSource->left = src_x;
629    sBltVP.rcSource->right = src_x + src_w;
630    sBltVP.rcSource->top = src_y;
631    sBltVP.rcSource->bottom = src_y + src_h;
632
633    if (subtitle == 1 && obj_surface->subpic_count) {
634        for (i = 0; i < obj_surface->subpic_count; i++) {
635            sBltVP.uiNumLayers += 1;
636
637            psb_calculate_subpic_size(obj_surface->width, obj_surface->height, dst_w, dst_h, surface_subpic);
638
639            pVaVideoSubpicMemInfo = psb_check_subpic_buffer(driver_data, surface_subpic);
640            if (!pVaVideoSubpicMemInfo) {
641                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get subpic PVR2DMEMINFO!\n", __func__);
642                return;
643            }
644
645            object_subpic_p obj_subpic = SUBPIC(surface_subpic->subpic_id);
646            CHECK_SURFACE(obj_subpic);
647            // sBltVP.AlphaBlendingFunc = PVR2D_ALPHA_OP_GLOBAL;
648            sBltVP.AlphaBlendingFunc = 3;
649            sBltVP.subpicGlobalAlpha[i] = obj_subpic->global_alpha;
650
651            sBltVP.sSrcSubpic[i].pSurfMemInfo = pVaVideoSubpicMemInfo;
652            sBltVP.sSrcSubpic[i].SurfOffset = 0;
653            sBltVP.sSrcSubpic[i].Stride = surface_subpic->stride;
654
655            if (surface_subpic->fourcc == VA_FOURCC_AI44)
656                sBltVP.sSrcSubpic[i].Format = MAKEFOURCC('A', 'I' , '4', '4');
657            else
658                sBltVP.sSrcSubpic[i].Format = surface_subpic->fourcc;
659
660            sBltVP.sSrcSubpic[i].SurfWidth = surface_subpic->subpic_srcw;
661            sBltVP.sSrcSubpic[i].SurfHeight = surface_subpic->subpic_srch;
662
663            sBltVP.rcSubpicSource[i].left = surface_subpic->subpic_srcx;
664            sBltVP.rcSubpicSource[i].right = surface_subpic->subpic_srcx + surface_subpic->subpic_srcw;
665            sBltVP.rcSubpicSource[i].top = surface_subpic->subpic_srcy;
666            sBltVP.rcSubpicSource[i].bottom = surface_subpic->subpic_srcy + surface_subpic->subpic_srch;
667
668            sBltVP.rcSubpicDest[i].left = surface_subpic->subpic_dstx;
669            sBltVP.rcSubpicDest[i].right = surface_subpic->subpic_dstx + surface_subpic->subpic_dstw;
670            sBltVP.rcSubpicDest[i].top = surface_subpic->subpic_dsty;
671            sBltVP.rcSubpicDest[i].bottom = surface_subpic->subpic_dsty + surface_subpic->subpic_dsth;
672
673            //only allocate memory once for palette
674            if (surface_subpic->fourcc == VA_FOURCC_AI44) {
675                if (!texture_priv->pal_meminfo[i]) {
676                    ePVR2DStatus = PVR2DMemAlloc(driver_data->hPVR2DContext, 16 * sizeof(unsigned int), 0, 0, &texture_priv->pal_meminfo[i]);
677                    if (ePVR2DStatus != PVR2D_OK) {
678                        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemAlloc error %d\n", __FUNCTION__, ePVR2DStatus);
679                        return;
680                    }
681                }
682
683                sBltVP.pPalMemInfo[i] = texture_priv->pal_meminfo[i];
684                tmp_palette = sBltVP.pPalMemInfo[i]->pBase;
685                memcpy(tmp_palette, surface_subpic->palette_ptr, 16 * sizeof(unsigned int));
686                sBltVP.PalOffset[i] = 0;
687            }
688            surface_subpic = surface_subpic->next;
689        }
690    }
691
692//#ifndef ANDROID /* MRST Android not enable this API, uncomment for MRST */
693    ePVR2DStatus = PVR2DBltVideo(driver_data->hPVR2DContext, &sBltVP);
694//#endif
695
696    if (ePVR2DStatus != PVR2D_OK)
697        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: failed to do PVR2DBltVideo with error code %d\n",
698                           __FUNCTION__, ePVR2DStatus);
699
700    if (wrap_dst) {
701        ePVR2DStatus = PVR2DMemFree(driver_data->hPVR2DContext, pDstMeminfo);
702        if (ePVR2DStatus != PVR2D_OK)
703            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: PVR2DMemFree error %d\n", __FUNCTION__, ePVR2DStatus);
704    }
705
706    driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
707    driver_data->last_displaying_surface = VA_INVALID_SURFACE;
708    obj_surface->display_timestamp = 0;
709}
710
711static void
712psb_setup_coeffs(struct psb_texture_s * pPriv)
713{
714    double yCoeff, uCoeff, vCoeff, Constant;
715    double fContrast;
716    double Y_offset, CbCr_offset, RGB_offset;
717    int bright_off = 0;
718    psb_transform_coeffs coeffs, transfer_matrix;
719    memset(&coeffs, 0, sizeof(psb_transform_coeffs));
720    memset(&transfer_matrix, 0, sizeof(psb_transform_coeffs));
721
722    /* Offsets in the input and output ranges are
723     * included in the constant of the transform equation
724     */
725    psb_select_transfermatrix(pPriv, &transfer_matrix,
726                              &Y_offset, &CbCr_offset, &RGB_offset);
727
728    /*
729     * It is at this point we should adjust the parameters for the procamp:
730     * - Brightness is handled as an offset of the Y parameter.
731     * - Contrast is an adjustment of the Y scale.
732     * - Saturation is a scaling of the U anc V parameters.
733     * - Hue is a rotation of the U and V parameters.
734     */
735
736    bright_off = pPriv->brightness.Value;
737    fContrast = (pPriv->contrast.Value + 100) / 100.0;
738
739    /* Apply hue and saturation correction to transfer matrix */
740    psb_transform_sathuecoeffs(&coeffs,
741                               &transfer_matrix,
742                               pPriv->hue.Value * Degree,
743                               pPriv->saturation.Value / 100.0);
744
745    /* Create coefficients to get component R
746     * (including brightness and contrast correction)
747     */
748    psb_create_coeffs(-1 * Y_offset, -1 * CbCr_offset, -1 * CbCr_offset,
749                      RGB_offset, coeffs.rY, coeffs.rCb, coeffs.rCr,
750                      bright_off, fContrast, &yCoeff, &uCoeff, &vCoeff,
751                      &Constant);
752
753    /* Convert transform operation from floating point to fixed point */
754    psb_convert_coeffs(yCoeff, uCoeff, vCoeff, Constant,        /* input coefficients */
755                       &pPriv->coeffs.rY, &pPriv->coeffs.rU,
756                       &pPriv->coeffs.rV, &pPriv->coeffs.rConst,
757                       &pPriv->coeffs.rShift);
758
759    /* Create coefficients to get component G
760     * (including brightness and contrast correction)
761     */
762    psb_create_coeffs(-1 * Y_offset, -1 * CbCr_offset, -1 * CbCr_offset,
763                      RGB_offset, coeffs.gY, coeffs.gCb, coeffs.gCr,
764                      bright_off, fContrast, &yCoeff, &uCoeff, &vCoeff,
765                      &Constant);
766
767    /* Convert transform operation from floating point to fixed point */
768    psb_convert_coeffs(yCoeff, uCoeff, vCoeff, Constant,
769                       /* tranfer matrix coefficients for G */
770                       &pPriv->coeffs.gY, &pPriv->coeffs.gU,
771                       &pPriv->coeffs.gV, &pPriv->coeffs.gConst,
772                       &pPriv->coeffs.gShift);
773
774    /* Create coefficients to get component B
775     * (including brightness and contrast correction)
776     */
777    psb_create_coeffs(-1 * Y_offset, -1 * CbCr_offset, -1 * CbCr_offset,
778                      RGB_offset, coeffs.bY, coeffs.bCb, coeffs.bCr,
779                      bright_off, fContrast, &yCoeff, &uCoeff, &vCoeff,
780                      &Constant);
781
782    /* Convert transform operation from floating point to fixed point */
783    psb_convert_coeffs(yCoeff, uCoeff, vCoeff, Constant,
784                       /* tranfer matrix coefficients for B */
785                       &pPriv->coeffs.bY, &pPriv->coeffs.bU,
786                       &pPriv->coeffs.bV, &pPriv->coeffs.bConst,
787                       &pPriv->coeffs.bShift);
788}
789
790/*
791  These are the corresponding matrices when using NominalRange_16_235
792  for the input surface and NominalRange_0_255 for the outpur surface:
793
794  static const psb_transform_coeffs s601 = {
795  1.164,                0,              1.596,
796  1.164,                -0.391,         -0.813,
797  1.164,                2.018,          0
798  };
799
800  static const psb_transform_coeffs s709 = {
801  1.164,                0,              1.793,
802  1.164,                -0.213,         -0.534,
803  1.164,                2.115,          0
804  };
805
806  static const psb_transform_coeffs s240M = {
807  1.164,                -0.0007,        1.793,
808  1.164,                -0.257,         -0.542,
809  1.164,                2.078,          0.0004
810  };
811*/
812
813/**
814 * Select which transfer matrix to use in the YUV->RGB conversion.
815 */
816static void
817psb_select_transfermatrix(struct psb_texture_s * pPriv,
818                          psb_transform_coeffs * transfer_matrix,
819                          double *Y_offset, double *CbCr_offset,
820                          double *RGB_offset)
821{
822    double RGB_scale, Y_scale, Cb_scale, Cr_scale;
823
824    /*
825     * Depending on the nominal ranges of the input YUV surface and the output RGB
826     * surface, it might be needed to perform some scaling on the transfer matrix.
827     * The excursion in the YUV values implies that the first column of the matrix
828     * must be divided by the Y excursion, and the second and third columns be
829     * divided by the U and V excursions respectively. The offset does not affect
830     * the values of the matrix.
831     * The excursion in the RGB values implies that all the values in the transfer
832     * matrix must be multiplied by the value of the excursion.
833     *
834     * Example: Conversion of the SMPTE 240M transfer matrix.
835     *
836     * Conversion from [Y', Pb, Pr] to [R', G', B'] in the range of [0, 1]. Y' is in
837     * the range of [0, 1]      and Pb and Pr in the range of [-0.5, 0.5].
838     *
839     * R'               1       -0.000657       1.575848                Y'
840     * G'       =       1       -0.226418       -0.476529       *       Pb
841     * B'               1       1.825958        0.000378                Pr
842     *
843     * Conversion from [Y', Cb, Cr] to {R', G', B'] in the range of [0, 1]. Y' has an
844     * excursion of 219 and an offset of +16, and CB and CR have excursions of +/-112
845     * and offset of +128, for a range of 16 through 240 inclusive.
846     *
847     * R'               1/219   -0.000657/224   1.575848/224            Y'       16
848     * G'       =       1/219   -0.226418/224   -0.476529/224   *       Cb - 128
849     * B'               1/219   1.825958/224    0.000378/224            Cr   128
850     *
851     * Conversion from [Y', Cb, Cr] to R'G'B' in the range [0, 255].
852     *
853     * R'                         1/219 -0.000657/224 1.575848/224                      Y'       16
854     * G'       =       255 * 1/219     -0.226418/224 -0.476529/224             *       Cb - 128
855     * B'                         1/219 1.825958/224  0.000378/224                      Cr   128
856     */
857
858    switch (pPriv->src_nominalrange) {
859    case PSB_NominalRange_0_255:
860        /* Y has a range of [0, 255], U and V have a range of [0, 255] */
861    {
862        double tmp = 0.0;
863
864        (void)tmp;
865    }                          /* workaroud for float point bug? */
866    Y_scale = 255.0;
867    *Y_offset = 0;
868    Cb_scale = Cr_scale = 255;
869    *CbCr_offset = 128;
870    break;
871    case PSB_NominalRange_16_235:
872    case PSB_NominalRange_Unknown:
873        /* Y has a range of [16, 235] and Cb, Cr have a range of [16, 240] */
874        Y_scale = 219;
875        *Y_offset = 16;
876        Cb_scale = Cr_scale = 224;
877        *CbCr_offset = 128;
878        break;
879    case PSB_NominalRange_48_208:
880        /* Y has a range of [48, 208] and Cb, Cr have a range of [48, 208] */
881        Y_scale = 160;
882        *Y_offset = 48;
883        Cb_scale = Cr_scale = 160;
884        *CbCr_offset = 128;
885        break;
886
887    default:
888        /* Y has a range of [0, 1], U and V have a range of [-0.5, 0.5] */
889        Y_scale = 1;
890        *Y_offset = 0;
891        Cb_scale = Cr_scale = 1;
892        *CbCr_offset = 0;
893        break;
894    }
895
896    /*
897     * 8-bit computer RGB,      also known as sRGB or "full-scale" RGB, and studio
898     * video RGB, or "RGB with  head-room and toe-room." These are defined as follows:
899     *
900     * - Computer RGB uses 8 bits for each sample of red, green, and blue. Black
901     * is represented by R = G = B = 0, and white is represented by R = G = B = 255.
902     * - Studio video RGB uses some number of bits N for each sample of red, green,
903     * and blue, where N is 8 or more. Studio video RGB uses a different scaling
904     * factor than computer RGB, and it has an offset. Black is represented by
905     * R = G = B = 16*2^(N-8), and white is represented by R = G = B = 235*2^(N-8).
906     * However, actual values may fall outside this range.
907     */
908    switch (pPriv->dst_nominalrange) {
909    case PSB_NominalRange_0_255:      // for sRGB
910    case PSB_NominalRange_Unknown:
911        /* R, G and B have a range of [0, 255] */
912        RGB_scale = 255;
913        *RGB_offset = 0;
914        break;
915    case PSB_NominalRange_16_235:     // for stRGB
916        /* R, G and B have a range of [16, 235] */
917        RGB_scale = 219;
918        *RGB_offset = 16;
919        break;
920    case PSB_NominalRange_48_208:     // for Bt.1361 RGB
921        /* R, G and B have a range of [48, 208] */
922        RGB_scale = 160;
923        *RGB_offset = 48;
924        break;
925    default:
926        /* R, G and B have a range of [0, 1] */
927        RGB_scale = 1;
928        *RGB_offset = 0;
929        break;
930    }
931
932    switch (pPriv->video_transfermatrix) {
933    case PSB_VideoTransferMatrix_BT709:
934        memcpy(transfer_matrix, &s709, sizeof(psb_transform_coeffs));
935        break;
936    case PSB_VideoTransferMatrix_BT601:
937        memcpy(transfer_matrix, &s601, sizeof(psb_transform_coeffs));
938        break;
939    case PSB_VideoTransferMatrix_SMPTE240M:
940        memcpy(transfer_matrix, &s240M, sizeof(psb_transform_coeffs));
941        break;
942    case PSB_VideoTransferMatrix_Unknown:
943        /*
944         * Specifies that the video transfer matrix is not specified.
945         * The default value is BT601 for standard definition (SD) video and BT709
946         * for high definition (HD) video.
947         */
948        if (1 /*pPriv->sVideoDesc.SampleWidth < 720 */) {       /* TODO, width selection */
949            memcpy(transfer_matrix, &s601, sizeof(psb_transform_coeffs));
950        } else {
951            memcpy(transfer_matrix, &s709, sizeof(psb_transform_coeffs));
952        }
953        break;
954    default:
955        break;
956    }
957
958    if (Y_scale != 1 || Cb_scale != 1 || Cr_scale != 1) {
959        /* Each column of the transfer matrix has to
960         * be scaled by the excursion of each component
961         */
962        psb_scale_transfermatrix(transfer_matrix, 1 / Y_scale, 1 / Cb_scale,
963                                 1 / Cr_scale);
964    }
965    if (RGB_scale != 1) {
966        /* All the values in the transfer matrix have to be multiplied
967         * by the excursion of the RGB components
968         */
969        psb_scale_transfermatrix(transfer_matrix, RGB_scale, RGB_scale,
970                                 RGB_scale);
971    }
972}
973
974static void
975psb_scale_transfermatrix(psb_transform_coeffs * transfer_matrix,
976                         double YColumScale, double CbColumScale,
977                         double CrColumnScale)
978{
979    /* First column of the transfer matrix */
980    transfer_matrix->rY *= YColumScale;
981    transfer_matrix->gY *= YColumScale;
982    transfer_matrix->bY *= YColumScale;
983
984    /* Second column of the transfer matrix */
985    transfer_matrix->rCb *= CbColumScale;
986    transfer_matrix->gCb *= CbColumScale;
987    transfer_matrix->bCb *= CbColumScale;
988
989    /* Third column of the transfer matrix */
990    transfer_matrix->rCr *= CrColumnScale;
991    transfer_matrix->gCr *= CrColumnScale;
992    transfer_matrix->bCr *= CrColumnScale;
993}
994
995/*
996 * Calculates the coefficintes of a YUV->RGB conversion based on
997 * the provided basis coefficients (already had HUe and Satu applied).
998 * Performs brightness and contrast adjustment as well as the required
999 * offsets to put into correct range for hardware conversion.
1000 */
1001static void
1002psb_create_coeffs(double yOff, double uOff, double vOff, double rgbOff,
1003                  double yScale, double uScale, double vScale,
1004                  double brightness, double contrast,
1005                  double *pYCoeff, double *pUCoeff, double *pVCoeff,
1006                  double *pConstant)
1007{
1008    *pYCoeff = yScale * contrast;
1009    *pUCoeff = uScale * contrast;
1010    *pVCoeff = vScale * contrast;
1011
1012    *pConstant = (((yOff + brightness) * yScale)
1013                  + (uOff * uScale) + (vOff * vScale)) * contrast + rgbOff;
1014}
1015
1016/*
1017 * Converts a floating point function in the form
1018 *    a*yCoeff + b*uCoeff + c * vCoeff + d
1019 *  Into a fixed point function of the forrm
1020 *   (a*pY + b * pU + c * pV + constant)>>pShift
1021 */
1022static void
1023psb_convert_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
1024                   double ConstantTerm, signed char *pY, signed char *pU,
1025                   signed char *pV, signed short *constant,
1026                   unsigned char *pShift)
1027{
1028    *pShift = 0;
1029
1030    Ycoeff *= 256;
1031    Ucoeff *= 256;
1032    Vcoeff *= 256;
1033    ConstantTerm *= 256;
1034    *pShift = 8;
1035
1036    /*
1037     * What we want to do is scale up the coefficients so that they just fit into their
1038     * allowed bits, so we are using signed maths giving us coefficients can be between +-128.
1039     * The constant can be between =- 32767.
1040     * The divide can be between 0 and 256 (on powers of two only).
1041     * A mathematical approach would be nice, but for simplicity do an iterative compare
1042     * and divide. Until something fits.
1043     */
1044    while (psb_check_coeffs(Ycoeff, Ucoeff, Vcoeff, ConstantTerm, *pShift)) {
1045        Ycoeff /= 2;
1046        Ucoeff /= 2;
1047        Vcoeff /= 2;
1048        ConstantTerm /= 2;
1049        (*pShift)--;
1050    }
1051    *pY = (signed char)(Ycoeff + 0.5);
1052    *pU = (signed char)(Ucoeff + 0.5);
1053    *pV = (signed char)(Vcoeff + 0.5);
1054    *constant = (signed short)(ConstantTerm + 0.5);
1055}
1056
1057/**
1058 * Checks if the specified coefficients are within the ranges required
1059 * and returns true if they are else false.
1060 */
1061static int
1062psb_check_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
1063                 double ConstantTerm, signed char byShift)
1064{
1065    if ((Ycoeff > 127) || (Ycoeff < -128)) {
1066        return 1;
1067    }
1068    if ((Ucoeff > 127) || (Ucoeff < -128)) {
1069        return 1;
1070    }
1071    if ((Vcoeff > 127) || (Vcoeff < -128)) {
1072        return 1;
1073    }
1074    if ((ConstantTerm > 32766) || (ConstantTerm < -32767)) {
1075        return 1;
1076    }
1077    return 0;
1078}
1079
1080static void
1081psb_transform_sathuecoeffs(psb_transform_coeffs * dest,
1082                           const psb_transform_coeffs * const source,
1083                           double fHue, double fSat)
1084{
1085    double fHueSatSin, fHueSatCos;
1086
1087    fHueSatSin = sin(fHue) * fSat;
1088    fHueSatCos = cos(fHue) * fSat;
1089
1090    dest->rY = source->rY;
1091    dest->rCb = source->rCb * fHueSatCos - source->rCr * fHueSatSin;
1092    dest->rCr = source->rCr * fHueSatCos + source->rCb * fHueSatSin;
1093
1094    dest->gY = source->gY;
1095    dest->gCb = source->gCb * fHueSatCos - source->gCr * fHueSatSin;
1096    dest->gCr = source->gCr * fHueSatCos + source->gCb * fHueSatSin;
1097
1098    dest->bY = source->bY;
1099    dest->bCb = source->bCb * fHueSatCos - source->bCr * fHueSatSin;
1100    dest->bCr = source->bCr * fHueSatCos + source->bCb * fHueSatSin;
1101}
1102
1103