| /* |
| * Copyright (c) 2011 Intel Corporation. All Rights Reserved. |
| * Copyright (c) Imagination Technologies Limited, UK |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Waldo Bastian <waldo.bastian@intel.com> |
| * Zeng Li <zeng.li@intel.com> |
| * Edward Lin <edward.lin@intel.com> |
| * |
| */ |
| |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <wsbm/wsbm_manager.h> |
| #include "psb_buffer.h" |
| #include "tng_cmdbuf.h" |
| #include "psb_def.h" |
| #include "psb_drv_debug.h" |
| #include "tng_hostcode.h" |
| #include "psb_ws_driver.h" |
| |
| #ifdef ANDROID |
| #include <linux/psb_drm.h> |
| #else |
| #include "psb_drm.h" |
| #endif |
| |
| #include "tng_trace.h" |
| |
| /* |
| * Buffer layout: |
| * cmd_base <= cmd_idx < CMD_END() == reloc_base |
| * reloc_base <= reloc_idx < RELOC_END() == (reloc_size) |
| */ |
| |
| #define RELOC_END(cmdbuf) (cmdbuf->cmd_base + cmdbuf->size) |
| #define CMD_END(cmdbuf) (cmdbuf->reloc_base) |
| #define RELOC_SIZE (0x3000) |
| #define CMD_SIZE (0x3000) |
| #define RELOC_MARGIN (0x0800) |
| #define CMD_MARGIN (0x0400) |
| #define MAX_CMD_COUNT 12 |
| #define MTX_SEG_SIZE (0x0800) |
| |
| /*! |
| ***************************************************************************** |
| * |
| * @Name Command word format |
| * |
| * @details Mask and shift values for command word |
| * |
| ****************************************************************************/ |
| |
| /* |
| * clear buffer |
| */ |
| void tng_cmdbuf_mem_unmap(tng_cmdbuf_p cmdbuf) |
| { |
| psb_buffer_unmap(&cmdbuf->frame_mem); |
| psb_buffer_unmap(&cmdbuf->jpeg_pic_params); |
| psb_buffer_unmap(&cmdbuf->jpeg_header_mem); |
| psb_buffer_unmap(&cmdbuf->jpeg_header_interface_mem); |
| return ; |
| } |
| |
| /* |
| * clear buffer |
| */ |
| static void tng_cmdbuf_clear(tng_cmdbuf_p cmdbuf, int flag) |
| { |
| switch (flag) { |
| default: |
| case 4: |
| psb_buffer_destroy(&cmdbuf->jpeg_header_mem); |
| case 3: |
| psb_buffer_destroy(&cmdbuf->jpeg_pic_params); |
| case 2: |
| case 1: |
| psb_buffer_destroy(&cmdbuf->frame_mem); |
| break; |
| } |
| |
| if (cmdbuf->size) { |
| psb_buffer_destroy(&cmdbuf->buf); |
| cmdbuf->size = 0; |
| } |
| if (cmdbuf->buffer_refs_allocated) { |
| free(cmdbuf->buffer_refs); |
| cmdbuf->buffer_refs = NULL; |
| cmdbuf->buffer_refs_allocated = 0; |
| } |
| } |
| |
| |
| /* |
| * Create command buffer |
| */ |
| |
| VAStatus tng_cmdbuf_create( |
| object_context_p obj_context, |
| psb_driver_data_p driver_data, |
| tng_cmdbuf_p cmdbuf) |
| { |
| context_ENC_p ctx = (context_ENC_p) obj_context->format_data; |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| unsigned int size = CMD_SIZE + RELOC_SIZE; |
| |
| cmdbuf->size = 0; |
| cmdbuf->cmd_base = NULL; |
| cmdbuf->cmd_idx = NULL; |
| cmdbuf->reloc_base = NULL; |
| cmdbuf->reloc_idx = NULL; |
| cmdbuf->buffer_refs_count = 0; |
| cmdbuf->buffer_refs_allocated = 10; |
| cmdbuf->buffer_refs = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated); |
| if (NULL == cmdbuf->buffer_refs) { |
| cmdbuf->buffer_refs_allocated = 0; |
| vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; |
| } |
| |
| if (VA_STATUS_SUCCESS == vaStatus) { |
| vaStatus = psb_buffer_create(driver_data, size, psb_bt_cpu_only, &cmdbuf->buf); |
| cmdbuf->size = size; |
| } |
| |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 0 \n", __FUNCTION__); |
| tng_cmdbuf_clear(cmdbuf, 1); |
| free(cmdbuf->buffer_refs); |
| cmdbuf->buffer_refs = NULL; |
| cmdbuf->buffer_refs_allocated = 0; |
| return vaStatus; |
| } |
| |
| cmdbuf->mem_size = tng_align_KB(TNG_HEADER_SIZE); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "mem size %d\n", __FUNCTION__, cmdbuf->mem_size); |
| /* create buffer information buffer */ |
| //DEBUG-FIXME |
| //tng__alloc_init_buffer(driver_data, COMM_CMD_FRAME_BUF_NUM * cmdbuf->mem_size, psb_bt_cpu_vpu, &cmdbuf->frame_mem); |
| |
| vaStatus = psb_buffer_create(driver_data, COMM_CMD_FRAME_BUF_NUM * cmdbuf->mem_size, psb_bt_cpu_vpu, &cmdbuf->frame_mem); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create xx \n", __FUNCTION__); |
| free(cmdbuf->buffer_refs); |
| cmdbuf->buffer_refs = NULL; |
| cmdbuf->buffer_refs_allocated = 0; |
| return vaStatus; |
| } |
| /* all cmdbuf share one MTX_CURRENT_IN_PARAMS since every MB has a MTX_CURRENT_IN_PARAMS structure |
| * and filling this structure for all MB is very time-consuming |
| */ |
| |
| /* create JPEG quantization buffer */ |
| vaStatus = psb_buffer_create(driver_data, ctx->jpeg_pic_params_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_pic_params); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 1 \n", __FUNCTION__); |
| tng_cmdbuf_clear(cmdbuf, 2); |
| return vaStatus; |
| } |
| |
| /* create JPEG MTX setup buffer */ |
| vaStatus = psb_buffer_create(driver_data, ctx->jpeg_header_mem_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_header_mem); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 2 \n", __FUNCTION__); |
| tng_cmdbuf_clear(cmdbuf, 3); |
| return vaStatus; |
| } |
| |
| /* create JPEG MTX setup interface buffer */ |
| vaStatus = psb_buffer_create(driver_data, ctx->jpeg_header_interface_mem_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_header_interface_mem); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 3 \n", __FUNCTION__); |
| tng_cmdbuf_clear(cmdbuf, 4); |
| return vaStatus; |
| } |
| |
| return vaStatus; |
| } |
| |
| /* |
| * Destroy buffer |
| */ |
| void tng_cmdbuf_destroy(tng_cmdbuf_p cmdbuf) |
| { |
| psb_buffer_destroy(&cmdbuf->frame_mem); |
| psb_buffer_destroy(&cmdbuf->jpeg_header_mem); |
| psb_buffer_destroy(&cmdbuf->jpeg_pic_params); |
| psb_buffer_destroy(&cmdbuf->jpeg_header_interface_mem); |
| |
| if (cmdbuf->size) { |
| psb_buffer_destroy(&cmdbuf->buf); |
| cmdbuf->size = 0; |
| } |
| if (cmdbuf->buffer_refs_allocated) { |
| free(cmdbuf->buffer_refs); |
| cmdbuf->buffer_refs = NULL; |
| cmdbuf->buffer_refs_allocated = 0; |
| } |
| return ; |
| } |
| |
| /* |
| * Reset buffer & map |
| * |
| * Returns 0 on success |
| */ |
| int tng_cmdbuf_reset(tng_cmdbuf_p cmdbuf) |
| { |
| int ret; |
| cmdbuf->cmd_base = NULL; |
| cmdbuf->cmd_idx = NULL; |
| cmdbuf->reloc_base = NULL; |
| cmdbuf->reloc_idx = NULL; |
| |
| cmdbuf->buffer_refs_count = 0; |
| cmdbuf->frame_mem_index = 0; |
| cmdbuf->cmd_count = 0; |
| cmdbuf->mem_size = tng_align_KB(TNG_HEADER_SIZE); |
| |
| ret = psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base); |
| if (ret) { |
| return ret; |
| } |
| |
| cmdbuf->cmd_start = cmdbuf->cmd_base; |
| cmdbuf->cmd_idx = (IMG_UINT32 *) cmdbuf->cmd_base; |
| |
| cmdbuf->reloc_base = cmdbuf->cmd_base + CMD_SIZE; |
| cmdbuf->reloc_idx = (struct drm_psb_reloc *) cmdbuf->reloc_base; |
| |
| /* Add ourselves to the buffer list */ |
| tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->buf); /* cmd buf == 0 */ |
| return ret; |
| } |
| |
| /* |
| * Unmap buffer |
| * |
| * Returns 0 on success |
| */ |
| int tng_cmdbuf_unmap(tng_cmdbuf_p cmdbuf) |
| { |
| cmdbuf->cmd_base = NULL; |
| cmdbuf->cmd_start = NULL; |
| cmdbuf->cmd_idx = NULL; |
| cmdbuf->reloc_base = NULL; |
| cmdbuf->reloc_idx = NULL; |
| cmdbuf->cmd_count = 0; |
| psb_buffer_unmap(&cmdbuf->buf); |
| return 0; |
| } |
| |
| |
| /* |
| * Reference an addtional buffer "buf" in the command stream |
| * Returns a reference index that can be used to refer to "buf" in |
| * relocation records, -1 on error |
| */ |
| int tng_cmdbuf_buffer_ref(tng_cmdbuf_p cmdbuf, psb_buffer_p buf) |
| { |
| int item_loc = 0; |
| |
| /*Reserve the same TTM BO twice will cause kernel lock up*/ |
| while ((item_loc < cmdbuf->buffer_refs_count) |
| && (wsbmKBufHandle(wsbmKBuf(cmdbuf->buffer_refs[item_loc]->drm_buf)) |
| != wsbmKBufHandle(wsbmKBuf(buf->drm_buf)))) |
| //while( (item_loc < cmdbuf->buffer_refs_count) && (cmdbuf->buffer_refs[item_loc] != buf) ) |
| { |
| item_loc++; |
| } |
| if (item_loc == cmdbuf->buffer_refs_count) { |
| /* Add new entry */ |
| if (item_loc >= cmdbuf->buffer_refs_allocated) { |
| /* Allocate more entries */ |
| int new_size = cmdbuf->buffer_refs_allocated + 10; |
| psb_buffer_p *new_array; |
| new_array = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * new_size); |
| if (NULL == new_array) { |
| return -1; /* Allocation failure */ |
| } |
| memcpy(new_array, cmdbuf->buffer_refs, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated); |
| free(cmdbuf->buffer_refs); |
| cmdbuf->buffer_refs_allocated = new_size; |
| cmdbuf->buffer_refs = new_array; |
| } |
| cmdbuf->buffer_refs[item_loc] = buf; |
| cmdbuf->buffer_refs_count++; |
| buf->status = psb_bs_queued; |
| } |
| return item_loc; |
| } |
| |
| /* Creates a relocation record for a DWORD in the mapped "cmdbuf" at address |
| * "addr_in_cmdbuf" |
| * The relocation is based on the device virtual address of "ref_buffer" |
| * "buf_offset" is be added to the device virtual address, and the sum is then |
| * right shifted with "align_shift". |
| * "mask" determines which bits of the target DWORD will be updated with the so |
| * constructed address. The remaining bits will be filled with bits from "background". |
| */ |
| void tng_cmdbuf_add_relocation(tng_cmdbuf_p cmdbuf, |
| IMG_UINT32 *addr_in_dst_buffer,/*addr of dst_buffer for the DWORD*/ |
| psb_buffer_p ref_buffer, |
| IMG_UINT32 buf_offset, |
| IMG_UINT32 mask, |
| IMG_UINT32 background, |
| IMG_UINT32 align_shift, |
| IMG_UINT32 dst_buffer, |
| IMG_UINT32 *start_of_dst_buffer) /*Index of the list refered by cmdbuf->buffer_refs */ |
| { |
| struct drm_psb_reloc *reloc = cmdbuf->reloc_idx; |
| uint64_t presumed_offset = wsbmBOOffsetHint(ref_buffer->drm_buf); |
| |
| reloc->where = addr_in_dst_buffer - start_of_dst_buffer; /* Offset in DWORDs */ |
| |
| reloc->buffer = tng_cmdbuf_buffer_ref(cmdbuf, ref_buffer); |
| ASSERT(reloc->buffer != -1); |
| |
| reloc->reloc_op = PSB_RELOC_OP_OFFSET; |
| #ifndef VA_EMULATOR |
| if (presumed_offset) { |
| IMG_UINT32 new_val = presumed_offset + buf_offset; |
| |
| new_val = ((new_val >> align_shift) << (align_shift << PSB_RELOC_ALSHIFT_SHIFT)); |
| new_val = (background & ~mask) | (new_val & mask); |
| *addr_in_dst_buffer = new_val; |
| } else { |
| *addr_in_dst_buffer = PSB_RELOC_MAGIC; |
| } |
| #else |
| /* indicate subscript of relocation buffer */ |
| *addr_in_dst_buffer = reloc - (struct drm_psb_reloc *)cmdbuf->reloc_base; |
| #endif |
| reloc->mask = mask; |
| reloc->shift = align_shift << PSB_RELOC_ALSHIFT_SHIFT; |
| reloc->pre_add = buf_offset; |
| reloc->background = background; |
| reloc->dst_buffer = dst_buffer; |
| cmdbuf->reloc_idx++; |
| |
| ASSERT(((void *)(cmdbuf->reloc_idx)) < RELOC_END(cmdbuf)); |
| } |
| |
| /* Prepare one command package */ |
| void tng_cmdbuf_insert_command( |
| object_context_p obj_context, |
| IMG_UINT32 stream_id, |
| IMG_UINT32 cmd_id, |
| IMG_UINT32 cmd_data, |
| psb_buffer_p data_addr, |
| IMG_UINT32 offset) |
| { |
| IMG_UINT32 cmd_word; |
| context_ENC_p ctx = (context_ENC_p) obj_context->format_data; |
| context_ENC_cmdbuf *ps_cmd = &(ctx->ctx_cmdbuf[stream_id]); |
| context_ENC_mem *ps_mem = &(ctx->ctx_mem[stream_id]); |
| tng_cmdbuf_p cmdbuf = obj_context->tng_cmdbuf; |
| psb_driver_data_p driver_data = ctx->obj_context->driver_data; |
| int interrupt_flags; |
| |
| //CMD composed by user space does not generate Interrupt |
| interrupt_flags = 0; |
| |
| assert(stream_id <= TOPAZHP_MAX_NUM_STREAMS); |
| |
| /* Write command to FIFO */ |
| { |
| cmd_word = F_ENCODE(stream_id, MTX_MSG_CORE) | |
| F_ENCODE(cmd_id, MTX_MSG_CMD_ID); |
| |
| if (cmd_id & MTX_CMDID_PRIORITY) { |
| /* increment the command counter */ |
| ps_cmd->ui32HighCmdCount++; |
| |
| /* Prepare high priority command */ |
| cmd_word |= F_ENCODE(1, MTX_MSG_PRIORITY) | |
| F_ENCODE(((ps_cmd->ui32LowCmdCount - 1) & 0xff) |(ps_cmd->ui32HighCmdCount << 8), MTX_MSG_COUNT); |
| } else { |
| /* Prepare low priority command */ |
| cmd_word |= |
| F_ENCODE(ps_cmd->ui32LowCmdCount & 0xff, MTX_MSG_COUNT); |
| ++(ps_cmd->ui32LowCmdCount); |
| } |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: cmd_id = 0x%08x\n", |
| __FUNCTION__, cmd_word); |
| *cmdbuf->cmd_idx++ = cmd_word; |
| } |
| |
| /* write command word into cmdbuf */ |
| *cmdbuf->cmd_idx++ = cmd_data; |
| /* Command data address */ |
| if (data_addr) { |
| if (cmd_id == MTX_CMDID_RC_UPDATE) { |
| *cmdbuf->cmd_idx++ = (IMG_UINT32)data_addr; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: data_addr = 0x%08x\n", |
| __FUNCTION__, *(cmdbuf->cmd_idx)); |
| } else { |
| if ((cmd_id >= MTX_CMDID_SETQUANT) && (cmd_id <= MTX_CMDID_SETUP)) { |
| if (cmd_id == MTX_CMDID_ISSUEBUFF) |
| TNG_RELOC_CMDBUF_START(cmdbuf->cmd_idx, offset, data_addr); |
| else |
| tng_cmdbuf_set_phys(cmdbuf->cmd_idx, 0, data_addr, offset, 0); |
| } else { |
| #ifdef _TNG_RELOC_ |
| TNG_RELOC_CMDBUF_START(cmdbuf->cmd_idx, offset, data_addr); |
| #else |
| tng_cmdbuf_set_phys(cmdbuf->cmd_idx, 0, data_addr, offset, 0); |
| #endif |
| } |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: data_addr = 0x%08x\n", |
| __FUNCTION__, *(cmdbuf->cmd_idx)); |
| cmdbuf->cmd_idx++; |
| } |
| } else { |
| *cmdbuf->cmd_idx++ = 0; |
| } |
| |
| if (cmd_id == MTX_CMDID_SW_FILL_INPUT_CTRL) { |
| *cmdbuf->cmd_idx++ = ctx->ui16IntraRefresh; |
| *cmdbuf->cmd_idx++ = ctx->sRCParams.ui32InitialQp; |
| *cmdbuf->cmd_idx++ = ctx->sRCParams.iMinQP; |
| *cmdbuf->cmd_idx++ = ctx->ctx_mem_size.mb_ctrl_in_params; |
| *cmdbuf->cmd_idx++ = ctx->ui32pseudo_rand_seed; |
| } |
| |
| if (cmd_id == MTX_CMDID_SW_UPDATE_AIR_SEND) { |
| *cmdbuf->cmd_idx++ = ctx->sAirInfo.i16AIRSkipCnt; |
| *cmdbuf->cmd_idx++ = ctx->sAirInfo.i32NumAIRSPerFrame; |
| *cmdbuf->cmd_idx++ = ctx->ctx_mem_size.mb_ctrl_in_params; |
| *cmdbuf->cmd_idx++ = ctx->ui32FrameCount[0]; |
| } |
| |
| if (cmd_id == MTX_CMDID_SW_UPDATE_AIR_CALC) { |
| *cmdbuf->cmd_idx++ = ctx->ctx_mem_size.first_pass_out_best_multipass_param; |
| *cmdbuf->cmd_idx++ = ctx->sAirInfo.i32SAD_Threshold; |
| *cmdbuf->cmd_idx++ = ctx->ui8EnableSelStatsFlags; |
| } |
| |
| /* Command data address */ |
| if (cmd_id == MTX_CMDID_SETVIDEO) { |
| *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ctx->bufs_writeback.drm_buf)); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: cmd_param = 0x%08x\n", |
| __FUNCTION__, *(cmdbuf->cmd_idx - 1)); |
| |
| if (data_addr) |
| *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(data_addr->drm_buf)); |
| |
| *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_mb_ctrl_in_params.drm_buf)); |
| *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_first_pass_out_params.drm_buf)); |
| *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_first_pass_out_best_multipass_param.drm_buf)); |
| } |
| |
| if (cmd_id == MTX_CMDID_SETUP_INTERFACE) { |
| *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ctx->bufs_writeback.drm_buf)); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: cmd_param = 0x%08x\n", |
| __FUNCTION__, *(cmdbuf->cmd_idx - 1)); |
| } |
| |
| if (cmd_id == MTX_CMDID_SHUTDOWN) { |
| *(cmdbuf->cmd_idx)++ = ctx->eCodec; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: cmd_param = 0x%08x\n", |
| __FUNCTION__, *(cmdbuf->cmd_idx - 1)); |
| } |
| |
| return ; |
| } |
| |
| |
| /* |
| * Advances "obj_context" to the next cmdbuf |
| * |
| * Returns 0 on success |
| */ |
| int tng_context_get_next_cmdbuf(object_context_p obj_context) |
| { |
| tng_cmdbuf_p cmdbuf; |
| int ret; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start obj_context->tng_cmdbuf = %x\n", __FUNCTION__, obj_context->tng_cmdbuf); |
| |
| if (obj_context->tng_cmdbuf) { |
| return 0; |
| } |
| |
| obj_context->cmdbuf_current++; |
| if (obj_context->cmdbuf_current >= TNG_MAX_CMDBUFS_ENCODE) { |
| obj_context->cmdbuf_current = 0; |
| } |
| |
| cmdbuf = obj_context->tng_cmdbuf_list[obj_context->cmdbuf_current]; |
| ret = tng_cmdbuf_reset(cmdbuf); |
| if (!ret) { |
| /* Success */ |
| obj_context->tng_cmdbuf = cmdbuf; |
| } |
| |
| // tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->pic_params); |
| // tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->slice_mem); |
| return ret; |
| } |
| |
| /* |
| * This is the user-space do-it-all interface to the drm cmdbuf ioctl. |
| * It allows different buffers as command- and reloc buffer. A list of |
| * cliprects to apply and whether to copy the clipRect content to all |
| * scanout buffers (damage = 1). |
| */ |
| /* |
| * Don't add debug statements in this function, it gets called with the |
| * DRM lock held and output to an X terminal can cause X to deadlock |
| */ |
| static int |
| ptgDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle, |
| unsigned cmdBufOffset, unsigned cmdBufSize, |
| unsigned relocBufHandle, unsigned relocBufOffset, |
| unsigned numRelocs, int __maybe_unused damage, |
| unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_rep) |
| { |
| drm_psb_cmdbuf_arg_t ca; |
| struct psb_validate_arg *arg_list; |
| int i, ret; |
| unsigned int retry = 0; |
| uint64_t mask = PSB_GPU_ACCESS_MASK; |
| |
| arg_list = (struct psb_validate_arg *) calloc(1, sizeof(struct psb_validate_arg) * buffer_count); |
| if (arg_list == NULL) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "Allocate memory failed\n"); |
| return -ENOMEM; |
| } |
| |
| for (i = 0; i < buffer_count; i++) { |
| struct psb_validate_arg *arg = &(arg_list[i]); |
| struct psb_validate_req *req = &arg->d.req; |
| |
| //memset(arg, 0, sizeof(*arg)); |
| req->next = (unsigned long) & (arg_list[i+1]); |
| |
| req->buffer_handle = wsbmKBufHandle(wsbmKBuf(buffer_list[i]->drm_buf)); |
| //req->group = 0; |
| req->set_flags = (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) & mask; |
| req->clear_flags = (~(PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE)) & mask; |
| #if 1 |
| req->presumed_gpu_offset = (uint64_t)wsbmBOOffsetHint(buffer_list[i]->drm_buf); |
| req->presumed_flags = PSB_USE_PRESUMED; |
| #else |
| req->presumed_flags = 0; |
| #endif |
| req->pad64 = (IMG_UINT32)buffer_list[i]->pl_flags; |
| #ifndef BAYTRAIL |
| req->unfence_flag = buffer_list[i]->unfence_flag; |
| #endif |
| } |
| arg_list[buffer_count-1].d.req.next = 0; |
| |
| memset(&ca, 0, sizeof(ca)); |
| |
| ca.buffer_list = (uint64_t)((unsigned long)arg_list); |
| ca.cmdbuf_handle = cmdBufHandle; |
| ca.cmdbuf_offset = cmdBufOffset; |
| ca.cmdbuf_size = cmdBufSize; |
| ca.reloc_handle = relocBufHandle; |
| ca.reloc_offset = relocBufOffset; |
| ca.num_relocs = numRelocs; |
| ca.engine = engine; |
| ca.fence_flags = fence_flags; |
| ca.fence_arg = (uint64_t)((unsigned long)fence_rep); |
| //ca.damage = damage; |
| |
| |
| do { |
| ret = drmCommandWrite(fd, ioctl_offset, &ca, sizeof(ca)); |
| if (ret == -EAGAIN || ret == -EBUSY) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "drmCommandWrite returns with %s, retry\n", |
| ret==-EAGAIN?"EAGAIN":"EBUSY"); |
| retry++; |
| } |
| } while (ret == -EAGAIN || ret == -EBUSY); |
| |
| if (retry > 0) |
| drv_debug_msg(VIDEO_DEBUG_ERROR,"drmCommandWrite tries %d time, finally %s with ret=%d\n", |
| retry, ret==0?"okay":"failed!", ret); |
| |
| if (ret) |
| goto out; |
| |
| for (i = 0; i < buffer_count; i++) { |
| struct psb_validate_arg *arg = &(arg_list[i]); |
| struct psb_validate_rep *rep = &arg->d.rep; |
| |
| if (!arg->handled) { |
| ret = -EFAULT; |
| goto out; |
| } |
| if (arg->ret != 0) { |
| ret = arg->ret; |
| goto out; |
| } |
| wsbmUpdateKBuf(wsbmKBuf(buffer_list[i]->drm_buf), |
| rep->gpu_offset, rep->placement, rep->fence_type_mask); |
| } |
| out: |
| free(arg_list); |
| for (i = 0; i < buffer_count; i++) { |
| /* |
| * Buffer no longer queued in userspace |
| */ |
| switch (buffer_list[i]->status) { |
| case psb_bs_queued: |
| buffer_list[i]->status = psb_bs_ready; |
| break; |
| |
| case psb_bs_abandoned: |
| psb_buffer_destroy(buffer_list[i]); |
| free(buffer_list[i]); |
| break; |
| |
| default: |
| /* Not supposed to happen */ |
| ASSERT(0); |
| } |
| } |
| |
| return ret; |
| } |
| |
| #if 0 |
| static struct _WsbmFenceObject * |
| lnc_fence_wait(psb_driver_data_p driver_data, |
| struct psb_ttm_fence_rep *fence_rep, int *status) |
| |
| { |
| struct _WsbmFenceObject *fence = NULL; |
| int ret = -1; |
| |
| /* copy fence information */ |
| if (fence_rep->error != 0) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "drm failed to create a fence" |
| " and has idled the HW\n"); |
| DEBUG_FAILURE_RET; |
| return NULL; |
| } |
| |
| fence = wsbmFenceCreate(driver_data->fence_mgr, fence_rep->fence_class, |
| fence_rep->fence_type, |
| (void *)fence_rep->handle, |
| 0); |
| if (fence) |
| *status = wsbmFenceFinish(fence, fence_rep->fence_type, 0); |
| |
| return fence; |
| } |
| #endif |
| |
| /* |
| * Submits the current cmdbuf |
| * |
| * Returns 0 on success |
| */ |
| int tng_context_submit_cmdbuf(object_context_p __maybe_unused obj_context) |
| { |
| return 0; |
| } |
| |
| |
| |
| /* |
| * FrameSkip is only meaningful for RC enabled mode |
| * Topaz raises this flag after surface N encoding is finished (vaSyncSurface gets back) |
| * then for the next encode surface N+1 (ctx->src_surface) frameskip flag is cleared in vaBeginPicuture |
| * and is always set in vaEndPicture:lnc_PatchRCMode |
| * vaQuerySurfaceStatus is supposed only to be called after vaEndPicture/vaSyncSurface, |
| * The caller should ensure the surface pertains to an encode context |
| */ |
| int tng_surface_get_frameskip(psb_driver_data_p __maybe_unused driver_data, |
| psb_surface_p surface, |
| int *frame_skip) |
| { |
| /* bit31 indicate if frameskip is already settled, it is used to record the frame skip flag for old surfaces |
| * bit31 is cleared when the surface is used as encode render target or reference/reconstrucure target |
| */ |
| if (GET_SURFACE_INFO_skipped_flag(surface) & SURFACE_INFO_SKIP_FLAG_SETTLED) { |
| *frame_skip = GET_SURFACE_INFO_skipped_flag(surface) & 1; |
| } else |
| *frame_skip = 0; |
| |
| return 0; |
| } |
| |
| VAStatus tng_set_frame_skip_flag(object_context_p obj_context) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_p ctx = (context_ENC_p) obj_context->format_data; |
| context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); |
| |
| if (ctx && ps_buf->previous_src_surface) { |
| SET_SURFACE_INFO_skipped_flag(ps_buf->previous_src_surface->psb_surface, 1); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n", |
| ps_buf->previous_src_surface->psb_surface); |
| } |
| |
| return vaStatus; |
| } |
| |
| |
| /* |
| * Flushes all cmdbufs |
| */ |
| int tng_context_flush_cmdbuf(object_context_p obj_context) |
| { |
| tng_cmdbuf_p cmdbuf = obj_context->tng_cmdbuf; |
| psb_driver_data_p driver_data = obj_context->driver_data; |
| unsigned int fence_flags; |
| struct psb_ttm_fence_rep fence_rep; |
| unsigned int reloc_offset; |
| unsigned int num_relocs; |
| int ret; |
| unsigned int cmdbuffer_size = (unsigned int) (((unsigned char *)(cmdbuf->cmd_idx)) - cmdbuf->cmd_start); /* In bytes */ |
| |
| ASSERT(cmdbuffer_size < CMD_SIZE); |
| ASSERT((void *) cmdbuf->cmd_idx < CMD_END(cmdbuf)); |
| /* LOCK */ |
| ret = LOCK_HARDWARE(driver_data); |
| if (ret) { |
| UNLOCK_HARDWARE(driver_data); |
| DEBUG_FAILURE_RET; |
| return ret; |
| } |
| |
| /* Now calculate the total number of relocations */ |
| reloc_offset = cmdbuf->reloc_base - cmdbuf->cmd_base; |
| num_relocs = (((unsigned char *) (cmdbuf->reloc_idx)) - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc); |
| |
| tng_cmdbuf_unmap(cmdbuf); |
| |
| ASSERT(NULL == cmdbuf->reloc_base); |
| |
| #ifdef DEBUG_TRACE |
| fence_flags = 0; |
| #else |
| fence_flags = DRM_PSB_FENCE_NO_USER; |
| #endif |
| |
| |
| wsbmWriteLockKernelBO(); |
| #if 1 //_PO_DEBUG_ |
| ret = ptgDRMCmdBuf(driver_data->drm_fd, driver_data->execIoctlOffset, /* FIXME Still use ioctl cmd? */ |
| cmdbuf->buffer_refs, cmdbuf->buffer_refs_count, wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)), |
| 0, cmdbuffer_size,/*unsigned cmdBufSize*/ |
| wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)), reloc_offset, num_relocs, |
| 0, LNC_ENGINE_ENCODE, fence_flags, &fence_rep); /* FIXME use LNC_ENGINE_ENCODE */ |
| #endif |
| wsbmWriteUnlockKernelBO(); |
| |
| UNLOCK_HARDWARE(driver_data); |
| |
| if (ret) { |
| obj_context->tng_cmdbuf = NULL; |
| |
| DEBUG_FAILURE_RET; |
| return ret; |
| } |
| |
| #if 0 /*DEBUG_TRACE*/ |
| int status = -1; |
| struct _WsbmFenceObject *fence = NULL; |
| |
| fence = lnc_fence_wait(driver_data, &fence_rep, &status); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_fence_wait returns: %d (fence=0x%08x)\n", status, fence); |
| |
| if (fence) |
| wsbmFenceUnreference(fence); |
| #endif |
| |
| obj_context->tng_cmdbuf = NULL; |
| |
| return 0; |
| } |
| |
| |
| void tng_cmdbuf_set_phys(IMG_UINT32 *dest_buf, int dest_num, |
| psb_buffer_p ref_buf, unsigned int ref_ofs, unsigned int ref_len) |
| { |
| int i = 0; |
| IMG_UINT32 addr_phys = (IMG_UINT32)wsbmBOOffsetHint(ref_buf->drm_buf) + ref_ofs; |
| |
| // drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: drm_buf 0x%08x, addr_phys 0x%08x, virt addr 0x%08x\n", __FUNCTION__, ref_buf->drm_buf, addr_phys, ref_buf->virtual_addr ); |
| |
| do { |
| dest_buf[i] = addr_phys; |
| ++i; |
| addr_phys += ref_len; |
| } while(i < dest_num); |
| return ; |
| } |
| |
| |
| int tng_get_pipe_number(object_context_p obj_context) |
| { |
| |
| context_ENC_p ctx = (context_ENC_p)(obj_context->format_data); |
| return ctx->ui8PipesToUse; |
| |
| } |
| |