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