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