psb_buffer.c revision c3077df94073dd4c035f86e5f1428e4611a0cf73
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 *    Waldo Bastian <waldo.bastian@intel.com>
27 *
28 */
29
30#include "psb_buffer.h"
31
32#include <errno.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <wsbm/wsbm_manager.h>
36
37#include "psb_drm.h"
38#include "psb_def.h"
39
40#include <pnw_cmdbuf.h>
41
42#include "pnw_jpeg.h"
43#include "pnw_H264ES.h"
44#include "lnc_H264ES.h"
45
46/*
47 * Create buffer
48 */
49VAStatus psb_buffer_create(psb_driver_data_p driver_data,
50                           unsigned int size,
51                           psb_buffer_type_t type,
52                           psb_buffer_p buf
53                          )
54{
55    VAStatus vaStatus = VA_STATUS_SUCCESS;
56    int allignment;
57    uint32_t placement;
58    int ret;
59
60    /* reset rar_handle to NULL */
61    buf->rar_handle = 0;
62    buf->buffer_ofs = 0;
63
64    buf->type = type;
65    buf->driver_data = driver_data; /* only for RAR buffers */
66
67    /* TODO: Mask values are a guess */
68    switch (type) {
69    case psb_bt_cpu_vpu:
70        allignment = 1;
71        placement = DRM_PSB_FLAG_MEM_MMU;
72        break;
73    case psb_bt_cpu_vpu_shared:
74        allignment = 1;
75        placement = DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_SHARED;
76        break;
77    case psb_bt_surface:
78        allignment = 0;
79        /* Xvideo will share surface buffer, set SHARED flag
80         */
81        if (getenv("PSB_VIDEO_SURFACE_MMU")) {
82            psb__information_message("Allocate surface from MMU heap\n");
83            placement = DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_SHARED;
84        } else {
85            psb__information_message("Allocate surface from TT heap\n");
86            placement = WSBM_PL_FLAG_TT | WSBM_PL_FLAG_SHARED;
87        }
88        break;
89    case psb_bt_vpu_only:
90        allignment = 1;
91        placement = DRM_PSB_FLAG_MEM_MMU;
92        break;
93
94    case psb_bt_cpu_only:
95        allignment = 1;
96        placement = WSBM_PL_FLAG_SYSTEM | WSBM_PL_FLAG_CACHED;
97        break;
98    case psb_bt_camera:
99        allignment = 1;
100        placement = TTM_PL_FLAG_CI | WSBM_PL_FLAG_SHARED;
101        break;
102    case psb_bt_rar:
103        allignment = 1;
104        placement = TTM_PL_FLAG_RAR | WSBM_PL_FLAG_SHARED;
105        break;
106    default:
107        vaStatus = VA_STATUS_ERROR_UNKNOWN;
108        DEBUG_FAILURE;
109        return vaStatus;
110    }
111    ret = LOCK_HARDWARE(driver_data);
112    if (ret) {
113        UNLOCK_HARDWARE(driver_data);
114        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
115        DEBUG_FAILURE_RET;
116        return vaStatus;
117    }
118
119#ifdef VA_EMULATOR
120    placement |= WSBM_PL_FLAG_SHARED;
121#endif
122
123#ifdef MSVDX_VA_EMULATOR
124    placement |= WSBM_PL_FLAG_SHARED;
125#endif
126
127    allignment = 4096; /* temporily more safe */
128
129    //psb__error_message("FIXME: should use geetpagesize() ?\n");
130    ret = wsbmGenBuffers(driver_data->main_pool, 1, &buf->drm_buf,
131                         allignment, placement);
132    if (!buf->drm_buf) {
133        psb__error_message("failed to gen wsbm buffers\n");
134        UNLOCK_HARDWARE(driver_data);
135        return VA_STATUS_ERROR_ALLOCATION_FAILED;
136    }
137
138    /* here use the placement when gen buffer setted */
139    ret = wsbmBOData(buf->drm_buf, size, NULL, NULL, 0);
140    UNLOCK_HARDWARE(driver_data);
141    if (ret) {
142        psb__error_message("failed to alloc wsbm buffers\n");
143        return VA_STATUS_ERROR_ALLOCATION_FAILED;
144    }
145
146    if (placement & WSBM_PL_FLAG_TT)
147        psb__information_message("Create BO with TT placement (%d byte),BO GPU offset hint=0x%08x\n",
148                                 size, wsbmBOOffsetHint(buf->drm_buf));
149
150    buf->pl_flags = placement;
151    buf->status = psb_bs_ready;
152    buf->wsbm_synccpu_flag = 0;
153
154    return VA_STATUS_SUCCESS;
155}
156
157
158/*
159 * buffer setstatus
160 *
161 * Returns 0 on success
162 */
163int psb_buffer_setstatus(psb_buffer_p buf, uint32_t set_placement, uint32_t clr_placement)
164{
165    int ret = 0;
166
167    ASSERT(buf);
168    ASSERT(buf->driver_data);
169
170    ret = wsbmBOSetStatus(buf->drm_buf, set_placement, clr_placement);
171    if (ret == 0)
172        buf->pl_flags = set_placement;
173
174    return ret;
175}
176
177
178VAStatus psb_buffer_reference(psb_driver_data_p driver_data,
179                              psb_buffer_p buf,
180                              psb_buffer_p reference_buf
181                             )
182{
183    int ret = 0;
184    VAStatus vaStatus = VA_STATUS_SUCCESS;
185
186    memcpy(buf, reference_buf, sizeof(*buf));
187    buf->drm_buf = NULL;
188
189    ret = LOCK_HARDWARE(driver_data);
190    if (ret) {
191        UNLOCK_HARDWARE(driver_data);
192        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
193        DEBUG_FAILURE_RET;
194        return vaStatus;
195    }
196
197    ret = wsbmGenBuffers(driver_data->main_pool,
198                         1,
199                         &buf->drm_buf,
200                         4096,  /* page alignment */
201                         0);
202    if (!buf->drm_buf) {
203        psb__error_message("failed to gen wsbm buffers\n");
204        UNLOCK_HARDWARE(driver_data);
205        return VA_STATUS_ERROR_ALLOCATION_FAILED;
206    }
207
208    ret = wsbmBOSetReferenced(buf->drm_buf, wsbmKBufHandle(wsbmKBuf(reference_buf->drm_buf)));
209    UNLOCK_HARDWARE(driver_data);
210    if (ret) {
211        psb__error_message("failed to alloc wsbm buffers\n");
212        return VA_STATUS_ERROR_ALLOCATION_FAILED;
213    }
214
215    return VA_STATUS_SUCCESS;
216}
217
218VAStatus psb_kbuffer_reference(psb_driver_data_p driver_data,
219                              psb_buffer_p buf,
220                              int kbuf_handle
221                             )
222{
223    int ret = 0;
224    VAStatus vaStatus = VA_STATUS_SUCCESS;
225
226    buf->drm_buf = NULL;
227
228    ret = LOCK_HARDWARE(driver_data);
229    if (ret) {
230        UNLOCK_HARDWARE(driver_data);
231        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
232        DEBUG_FAILURE_RET;
233        return vaStatus;
234    }
235
236    ret = wsbmGenBuffers(driver_data->main_pool,
237                         1,
238                         &buf->drm_buf,
239                         4096,  /* page alignment */
240                         0);
241    if (!buf->drm_buf) {
242        psb__error_message("failed to gen wsbm buffers\n");
243        UNLOCK_HARDWARE(driver_data);
244        return VA_STATUS_ERROR_ALLOCATION_FAILED;
245    }
246
247    ret = wsbmBOSetReferenced(buf->drm_buf,kbuf_handle );
248    UNLOCK_HARDWARE(driver_data);
249    if (ret) {
250        psb__error_message("failed to alloc wsbm buffers\n");
251        return VA_STATUS_ERROR_ALLOCATION_FAILED;
252    }
253    buf->pl_flags = wsbmBOPlacementHint(buf->drm_buf);
254
255    return VA_STATUS_SUCCESS;
256}
257/*
258 * Destroy buffer
259 */
260void psb_buffer_destroy(psb_buffer_p buf)
261{
262    ASSERT(buf);
263    if (buf->drm_buf == NULL)
264        return;
265    if (psb_bs_unfinished != buf->status) {
266        ASSERT(buf->driver_data);
267        wsbmBOUnreference(&buf->drm_buf);
268        if (buf->rar_handle)
269            buf->rar_handle = 0;
270        buf->driver_data = NULL;
271        buf->status = psb_bs_unfinished;
272    }
273}
274
275/*
276 * Map buffer
277 *
278 * Returns 0 on success
279 */
280int psb_buffer_map(psb_buffer_p buf, void **address /* out */)
281{
282    int ret;
283
284    ASSERT(buf);
285    ASSERT(buf->driver_data);
286
287    /* multiple mapping not allowed */
288    if (buf->wsbm_synccpu_flag) {
289        psb__information_message("Multiple mapping request detected, unmap previous mapping\n");
290        psb__information_message("Need to fix application to unmap at first, then request second mapping request\n");
291
292        psb_buffer_unmap(buf);
293    }
294
295    /* don't think TG deal with READ/WRITE differently */
296    buf->wsbm_synccpu_flag = WSBM_SYNCCPU_READ | WSBM_SYNCCPU_WRITE;
297#ifdef DEBUG_TRACE
298    wsbmBOWaitIdle(buf->drm_buf, 0);
299#else
300    ret = wsbmBOSyncForCpu(buf->drm_buf, buf->wsbm_synccpu_flag);
301    if (ret) {
302        psb__error_message("faild to sync bo for cpu\n");
303        return ret;
304    }
305#endif
306
307    if (buf->type == psb_bt_user_buffer)
308        *address = buf->user_ptr;
309    else
310        *address = wsbmBOMap(buf->drm_buf, buf->wsbm_synccpu_flag);
311
312    if (*address == NULL) {
313        psb__error_message("failed to map buffer\n");
314        return -1;
315    }
316
317    return 0;
318
319}
320
321/*
322 * Unmap buffer
323 *
324 * Returns 0 on success
325 */
326int psb_buffer_unmap(psb_buffer_p buf)
327{
328    ASSERT(buf);
329    ASSERT(buf->driver_data);
330
331    if (buf->wsbm_synccpu_flag)
332        (void) wsbmBOReleaseFromCpu(buf->drm_buf, buf->wsbm_synccpu_flag);
333
334    buf->wsbm_synccpu_flag = 0;
335
336    if (buf->type != psb_bt_user_buffer)
337        wsbmBOUnmap(buf->drm_buf);
338
339    return 0;
340}
341
342
343/*
344 * Return special data structure for codedbuffer
345 *
346 * Returns 0 on success
347 */
348#define CONFIG(id)  ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
349#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
350int psb_codedbuf_map_mangle(
351    VADriverContextP ctx,
352    object_buffer_p obj_buffer,
353    void **pbuf /* out */
354)
355{
356    object_context_p obj_context = obj_buffer->context;
357    INIT_DRIVER_DATA;
358    VACodedBufferSegment *p = &obj_buffer->codedbuf_mapinfo[0];
359    void *raw_codedbuf;
360    VAStatus vaStatus = VA_STATUS_SUCCESS;
361    unsigned int next_buf_off;
362    int i;
363
364    if (NULL == pbuf) {
365        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
366        return vaStatus;
367    }
368
369    if (NULL == obj_context) {
370        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
371        DEBUG_FAILURE;
372
373        psb_buffer_unmap(obj_buffer->psb_buffer);
374        obj_buffer->buffer_data = NULL;
375
376        return vaStatus;
377    }
378
379    raw_codedbuf = *pbuf;
380    /* reset the mapinfo */
381    memset(obj_buffer->codedbuf_mapinfo, 0, sizeof(obj_buffer->codedbuf_mapinfo));
382
383    *pbuf = p = &obj_buffer->codedbuf_mapinfo[0];
384    if (IS_MRST(driver_data)) {
385        /* one segment */
386        p->size = *((unsigned long *) raw_codedbuf); /* 1st DW is the size */
387        p->status = *((unsigned long *) raw_codedbuf + 1); /* 2nd DW
388                                                        * is rc status */
389        p->reserved = 0;
390        p->buf = (void *)((unsigned long *) raw_codedbuf + 4); /* skip 4DWs */
391        lnc_H264_append_aux_info(obj_context,
392                                 obj_buffer,
393                                 (unsigned char *)p->buf,
394                                 &(p->size));
395    } else { /* MFLD */
396        object_config_p obj_config = CONFIG(obj_context->config_id);
397
398        if (NULL == obj_config) {
399            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
400            DEBUG_FAILURE;
401
402            psb_buffer_unmap(obj_buffer->psb_buffer);
403            obj_buffer->buffer_data = NULL;
404
405            return vaStatus;
406        }
407
408        if (VAProfileJPEGBaseline != obj_config->profile
409            && (*((unsigned long *) raw_codedbuf + 1) & SKIP_NEXT_FRAME) != 0) {
410            /*Set frame skip flag*/
411            pnw_set_frame_skip_flag(obj_context);
412        }
413        switch (obj_config->profile) {
414        case VAProfileMPEG4Simple:
415        case VAProfileMPEG4AdvancedSimple:
416        case VAProfileMPEG4Main:
417            /* one segment */
418            p->size = *((unsigned long *) raw_codedbuf);
419            p->buf = (void *)((unsigned long *) raw_codedbuf + 4); /* skip 4DWs */
420            psb__information_message("coded buffer size %d\n", p->size);
421            break;
422
423        case VAProfileH264Baseline:
424        case VAProfileH264Main:
425        case VAProfileH264High:
426        case VAProfileH264ConstrainedBaseline:
427            /* 1st segment */
428            p->size = *((unsigned long *) raw_codedbuf);
429            p->buf = (void *)((unsigned long *) raw_codedbuf + 4); /* skip 4DWs */
430
431            psb__information_message("1st segment coded buffer size %d\n", p->size);
432            if (pnw_get_parallel_core_number(obj_context) == 2) {
433                /*The second part of coded buffer which generated by core 2 is the
434                 * first part of encoded clip, while the first part of coded buffer
435                 * is the second part of encoded clip.*/
436                next_buf_off = ~0xf & (obj_buffer->size / pnw_get_parallel_core_number(obj_context));
437                p->next = &p[1];
438                p[1].size = p->size;
439                p[1].buf = p->buf;
440                p[1].next = NULL;
441                p->size = *(unsigned long *)((unsigned long)raw_codedbuf + next_buf_off);
442                p->buf = (void *)(((unsigned long *)((unsigned long)raw_codedbuf + next_buf_off)) + 4); /* skip 4DWs */
443                psb__information_message("2nd segment coded buffer offset: 0x%08x,  size: %d\n",
444                                         next_buf_off, p->size);
445            } else
446                p->next = NULL;
447            break;
448
449        case VAProfileH263Baseline:
450            /* one segment */
451            p->size = *((unsigned long *) raw_codedbuf);
452            p->buf = (void *)((unsigned long *) raw_codedbuf + 4); /* skip 4DWs */
453            psb__information_message("coded buffer size %d\n", p->size);
454            break;
455
456        case VAProfileJPEGBaseline:
457            /* 3~6 segment
458                 */
459            pnw_jpeg_AppendMarkers(obj_context, raw_codedbuf);
460            next_buf_off = 0;
461            /*Max resolution 4096x4096 use 6 segments*/
462            for (i = 0; i < PNW_JPEG_MAX_SCAN_NUM + 1; i++) {
463                p->size = *(unsigned long *)((unsigned long)raw_codedbuf + next_buf_off);
464                p->buf = (void *)((unsigned long *)((unsigned long)raw_codedbuf + next_buf_off) + 4);  /* skip 4DWs */
465                next_buf_off = *((unsigned long *)((unsigned long)raw_codedbuf + next_buf_off) + 3);
466
467                psb__information_message("JPEG coded buffer segment %d size: %d\n", i, p->size);
468                psb__information_message("JPEG coded buffer next segment %d offset: %d\n", i + 1, next_buf_off);
469
470                if (next_buf_off == 0) {
471                    p->next = NULL;
472                    break;
473                } else
474                    p->next = &p[1];
475                p++;
476            }
477            break;
478
479        default:
480            psb__error_message("unexpected case\n");
481
482            psb_buffer_unmap(obj_buffer->psb_buffer);
483            obj_buffer->buffer_data = NULL;
484            break;
485        }
486    }
487
488    return 0;
489}
490
491int psb_buffer_sync(psb_buffer_p buf)
492{
493    int ret;
494
495    ASSERT(buf);
496    ASSERT(buf->driver_data);
497
498    ret = wsbmBOSyncForCpu(buf->drm_buf, buf->wsbm_synccpu_flag);
499    if (ret) {
500        psb__error_message("faild to sync bo for cpu\n");
501        return VA_STATUS_ERROR_UNKNOWN;
502    }
503
504    return VA_STATUS_SUCCESS;
505}
506