• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
86 typedef struct _psb_transform_coeffs_ {
87     double rY, rCb, rCr;
88     double gY, gCb, gCr;
89     double bY, bCb, bCr;
90 } psb_transform_coeffs;
91 
92 typedef 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 
100 typedef 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  */
117 static psb_transform_coeffs s601 = {
118     1, -0.000001, 1.402,
119     1, -0.344136, -0.714136,
120     1, 1.772, 0
121 };
122 
123 static psb_transform_coeffs s709 = {
124     1, 0, 1.5748,
125     1, -0.187324, -0.468124,
126     1, 1.8556, 0
127 };
128 
129 static psb_transform_coeffs s240M = {
130     1, -0.000657, 1.575848,
131     1, -0.226418, -0.476529,
132     1, 1.825958, 0.000378
133 };
134 
135 static void psb_setup_coeffs(struct psb_texture_s * pPriv);
136 static void psb_scale_transfermatrix(psb_transform_coeffs * transfer_matrix,
137                                      double YColumScale, double CbColumScale,
138                                      double CrColumnScale);
139 static 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);
143 static 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);
148 static 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);
152 static int psb_check_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
153                             double ConstantTerm, signed char byShift);
154 static void
155 psb_transform_sathuecoeffs(psb_transform_coeffs * dest,
156                            const psb_transform_coeffs * const source,
157                            double fHue, double fSat);
158 
PVRCalculateStride(unsigned long widthInPixels,unsigned int bitsPerPixel,unsigned int stride_alignment)159 static 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 
pvr_context_create(unsigned char ** pvr_ctx)165 static 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 
200 out:
201     if (pvr_devs)
202         free(pvr_devs);
203 
204     return ret;
205 }
206 
psb_fix_drmfd_closesequence(psb_driver_data_p driver_data)207 void 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 
psb_ctexture_init(VADriverContextP ctx)213 int 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 
psb_ctexture_deinit(VADriverContextP ctx)278 void 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 */
psb_calculate_subpic_size(int surf_width,int surf_height,int dst_w,int dst_h,PsbVASurfaceRec * surface_subpic)341 static 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 
psb_check_subpic_buffer(psb_driver_data_p driver_data,PsbVASurfaceRec * surface_subpic)370 static 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 
psb_init_surface_pvr2dbuf(psb_driver_data_p driver_data)425 void 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 
psb_free_surface_pvr2dbuf(psb_driver_data_p driver_data)437 void 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 
psb_wrap_surface_pvr2dbuf(psb_driver_data_p driver_data,VASurfaceID surface)464 static 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
524 void 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 
716 static void
psb_setup_coeffs(struct psb_texture_s * pPriv)717 psb_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  */
821 static void
psb_select_transfermatrix(struct psb_texture_s * pPriv,psb_transform_coeffs * transfer_matrix,double * Y_offset,double * CbCr_offset,double * RGB_offset)822 psb_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 
979 static void
psb_scale_transfermatrix(psb_transform_coeffs * transfer_matrix,double YColumScale,double CbColumScale,double CrColumnScale)980 psb_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  */
1006 static void
psb_create_coeffs(double yOff,double uOff,double vOff,double rgbOff,double yScale,double uScale,double vScale,double brightness,double contrast,double * pYCoeff,double * pUCoeff,double * pVCoeff,double * pConstant)1007 psb_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  */
1027 static void
psb_convert_coeffs(double Ycoeff,double Ucoeff,double Vcoeff,double ConstantTerm,signed char * pY,signed char * pU,signed char * pV,signed short * constant,unsigned char * pShift)1028 psb_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  */
1066 static int
psb_check_coeffs(double Ycoeff,double Ucoeff,double Vcoeff,double ConstantTerm,signed char byShift)1067 psb_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 
1085 static void
psb_transform_sathuecoeffs(psb_transform_coeffs * dest,const psb_transform_coeffs * const source,double fHue,double fSat)1086 psb_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