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