This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: Linux
I need to rotate the output of the SGX544 OpenGL rendering cycle using the GC320. I have it working, but right now it requires 1 memcpy. I need to have zero copies for this operation.
The problem is that I cannot call the GC320 gcoSURF_SetBuffer() function with the memory mapped pointer from OpenGL's GEM BO backing store. If I do this, I immediately get an unrecoverable Linux Kernel GC320 Driver exception and have to reset the board. I have to copy it first, and call gcoSURF_SetBuffer() with the destination pointer of the copy operation.
Another interesting point is that if I memcpy the mmap'ed BO pointer, but then use the original mmap'ed BO pointer passed to gcoSURF_SetBuffer(), it seems to work. Something happens when I memcpy the mmap'ed BO pointer that causes the GC320 driver to be able to use the data with gcoSURF_SetBuffer.
My rendering code looks like this:
m_OGLController->paintGL(); m_OGLController->swapBuffers(); m_NextBo = gbm_surface_lock_front_buffer(m_Gbm->m_GBMSurface); m_Fb = m_DRMController->drmFbGetFromBo(m_NextBo); gbm_surface_release_buffer(m_Gbm->m_GBMSurface, m_NextBo);
m_Fb is this structure:
struct drm_fb *m_Fb; ... // A GBM buffer ( GBM-Buf ) object allocated from the DRM device // This can be set on a DRM Plane struct drm_fb { struct gbm_bo *bo; uint32_t fb_id; };
The memcpy looks like this:
// Copy data otherwise GC320 Driver Crashes memcpy(cpyFrame,gpuMmapFrame,dmaBuf.height * dmaBuf.width * 4);
The rotation code that includes the memcpy is contained in this function:
// Schedule an update drmModeAtomicReqPtr req = drmModeAtomicAlloc(); { // This is in a background thread and we want to protect shared vars QMutexLocker locker(&m_VSyncMutex); // Rotate the frame for LCD using GC320 dmabuf_buffer dmaBuf = m_DRMController->drmGetDmaBufFromBo(m_Fb->bo); // Switch size of backing store based on input argument QString selectedDisplay = qApp->property("DESIRED-SCREEN").toString(); if ( selectedDisplay.toLower() == "lcd" || selectedDisplay.toLower() == "both" ) { /* This is a hacky way to mmap the GBM BO. */ /* Ideally there should be GBM API to mmap the buffer */ /* NOTE: The address obtained is virtual address. */ union gbm_bo_handle handleUnion = gbm_bo_get_handle(m_Fb->bo); struct drm_omap_gem_info gemInfo; char *gpuMmapFrame = NULL; gemInfo.handle = handleUnion.s32; int ret = drmCommandWriteRead(m_DRMController->m_Fd, DRM_OMAP_GEM_INFO,&gemInfo, sizeof(gemInfo)); if (ret) { qDebug() << "RenderingManager::drmCommandWriteRead(): Cannot set write/read"; } else { // Mmap the frame gpuMmapFrame = (char *)mmap(0, gemInfo.size, PROT_READ | PROT_WRITE, MAP_SHARED,m_DRMController->m_Fd, gemInfo.offset); if ( gpuMmapFrame && gpuMmapFrame != MAP_FAILED ) { // For now need to copy the frame to rotate it char *cpyFrame = NULL; cpyFrame = (char*)malloc(sizeof(char) * dmaBuf.width * dmaBuf.height * 4); if ( cpyFrame ) { // Copy data otherwise GC320 Driver Crashes memcpy(cpyFrame,gpuMmapFrame,dmaBuf.height * dmaBuf.width * 4); // Perform the rotation with the gc320 m_GC320Controller->renderRGBARotate90(cpyFrame, dmaBuf.width, dmaBuf.height); // Get the dmabuf handle quint32 gc320DMABufHandle = m_GC320Controller->getOutputDmaBufHandle(); ///////////////////////////////////////////////////////////////////// // For each Composited / Rotated DMABUF - import the bo once so we can pass that to the egl image generation struct rotatedBoDmaBuf { gbm_bo *bo; int fd; }; // Store the dma buf info rotatedBoDmaBuf rotatedBo; // Setup RGB import data struct gbm_import_fd_data gbm_rotated_dmabuf = { .fd = gc320DMABufHandle, .width = 480, .height = 800, .stride = 480 * 4, .format = GBM_FORMAT_ARGB8888 }; gbm_device* currentGbmDev = m_OGLController->getGBMDev(); rotatedBo.bo = gbm_bo_import(currentGbmDev, GBM_BO_IMPORT_FD, &gbm_rotated_dmabuf, GBM_BO_USE_SCANOUT); drm_fb *rotatedFb = m_DRMController->drmFbGetFromBo(rotatedBo.bo); // Update LCD drmModeAtomicAddProperty(req, m_DRMController->m_DrmPlaneId[3], 14, rotatedFb->fb_id); // Unmap it munmap(gpuMmapFrame,SCREEN_HEIGHT*SCREEN_WIDTH*4); // Free it free(cpyFrame); } } } } else { // Update HDMI //drmModeAtomicAddProperty(req, m_DRMController->m_DrmPlaneId[3], 14, m_Fb->fb_id); } } // VSync commit int ret = drmModeAtomicCommit(m_DRMController->m_Fd, req, DRM_MODE_ATOMIC_TEST_ONLY, 0); if(!ret){ drmModeAtomicCommit(m_DRMController->m_Fd, req, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, &m_WaitingForFlip); } else { fprintf(stderr,"RenderingManager::PageFlip: Failed to add plane atomically: %s\n", strerror(errno)); } drmModeAtomicFree(req); // Wait for an VSync update FD_ZERO(&m_Fds); FD_SET(m_DRMController->m_Fd, &m_Fds); while (m_WaitingForFlip) { ret = select(m_DRMController->m_Fd + 1, &m_Fds, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr,"RenderingManager::PageFlip: Error - Select err: %s\n", strerror(errno)); break; } else if (ret == 0) { fprintf(stderr,"RenderingManager::PageFlip: Error - Select timeout!\n"); break; } else if (FD_ISSET(0, &m_Fds)) { fprintf(stderr,"RenderingManager::PageFlip: Warning - User interrupted!\n"); break; } drmHandleEvent(m_DRMController->m_Fd, &m_Evctx); } // Waiting for flip again m_WaitingForFlip = 1;
If I do not include the memcpy, and pass the "gpuMmapFrame" directly to the GC320 function, I get the following error on the Linux Kernel console:
[ 8063.964224] Unable to handle kernel paging request at virtual address ffffc53c
[ 8063.971555] pgd = ecd29180
[ 8063.974276] [ffffc53c] *pgd=80000080007003, *pmd=affaa003, *pte=00000000
[ 8063.981060] Internal error: Oops: 207 [#1] PREEMPT SMP ARM
[ 8063.986568] Modules linked in: vfb galcore(O) cfg80211 rpmsg_rpc snd_soc_omap_hdmi_audio snd_soc_omap snd_soc_core snd_pcm_dmaengine snd_pcm snd_timer snd soundcore virtio_rpmsg_bus omapdrm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops panel_dpi encoder_tpd12s015 connector_hdmi omapdss omapdss_base phy_omap_usb2 pruss omap_wdt phy_ti_pipe3 phy_omap_control ti_vpe ti_vip ti_sc ti_csc v4l2_mem2mem ti_vpdma videobuf2_dma_contig videobuf2_memops videobuf2_v4l2 pvrsrvkm(O) videobuf2_core dwc3_omap drm rtc_omap pwm_tiehrpwm flk_ti_mt9p031 comp_mir_hp aptina_pll v4l2_common videodev media rtc_palmas rtc_m41t80 spi_omap2_mcspi omap_remoteproc remoteproc virtio virtio_ring uio_pdrv_genirq uio cryptodev(O) autofs4
[ 8064.051100] CPU: 1 PID: 7282 Comm: Thread (pooled) Tainted: G O 4.4.41 #1
[ 8064.059049] Hardware name: Generic DRA74X (Flattened Device Tree)
[ 8064.065166] task: d2689e00 ti: ecf36000 task.ti: ecf36000
[ 8064.070596] PC is at __get_page_tail+0x1c/0x138
[ 8064.075185] LR is at gckOS_MapUserMemory+0x804/0xac8 [galcore]
[ 8064.081043] pc : [<c00e1950>] lr : [<bf532348>] psr: 200f0013
[ 8064.081043] sp : ecf37c80 ip : ecf37c98 fp : ecf37c94
[ 8064.092568] r10: c0718904 r9 : ae489000 r8 : c078b8c0
[ 8064.097813] r7 : ee49e000 r6 : 00000000 r5 : ffeee448 r4 : ee6c78b8
[ 8064.104366] r3 : ffffc538 r2 : 00000000 r1 : 00080000 r0 : ee49e000
[ 8064.110920] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
[ 8064.118084] Control: 30c5387d Table: acd29180 DAC: 55555555
[ 8064.123854] Process Thread (pooled) (pid: 7282, stack limit = 0xecf36210)
[ 8064.130669] Stack: (0xecf37c80 to 0xecf38000)
[ 8064.135045] 7c80: ee6c78b8 ffeee448 ecf37d24 ecf37c98 bf532348 c00e1940 00000001 00000000
[ 8064.143258] 7ca0: eea50800 00000000 c00a4b98 eea507fc ae489000 ffffe000 ffeee000 eea50800
[ 8064.151471] 7cc0: 000005e4 00000179 00000000 ecd29140 fffffff2 ae489000 ffffffff eea50800
[ 8064.159684] 7ce0: 00000177 ed2a4000 00003548 00000000 ffffffff 00000000 ffffe000 00000000
[ 8064.167895] 7d00: ecf37db0 ed2a4e00 00000001 ffffffff 00000000 00000000 ecf37d84 ecf37d28
[ 8064.176107] 7d20: bf539c98 bf531b50 00177000 ecf37d44 ecf37dec c9177840 00000000 ecf37d48
[ 8064.184319] 7d40: 00000000 00000000 00000000 00001c55 c456f8e8 b2f1d000 ffffffff 00000000
[ 8064.192530] 7d60: ecf36000 ee04be00 c5ab1680 00007530 ecf37d90 ecf36000 ecf37f14 ecf37d88
[ 8064.200741] 7d80: bf536428 bf5390f0 ecf37e0c ecf37d98 ae286a10 00000000 00000140 00000000
[ 8064.208952] 7da0: ae286a10 00000000 00000140 00000000 0000000b 00000002 02b9606c b6de3f8e
[ 8064.217164] 7dc0: 00000028 b6de2894 b6f56ce8 b6f444a4 ae489000 00000000 ffffffff 00000000
[ 8064.225377] 7de0: 00177000 00000000 00000000 00000000 ae286a98 572c0d98 00000000 00000000
[ 8064.233588] 7e00: ae286a98 b6de3f8e ae286ab8 ae286ac0 ae286b2c b6f360e9 ae286ac0 b6f57ab4
[ 8064.241801] 7e20: 00000007 00000000 00000005 00000000 00000001 b6f50810 b609c41c b6f4c000
[ 8064.250013] 7e40: ae286c4c ae286d00 00000000 b6f509c8 b6f50810 b6f509c8 079105f9 b2f00010
[ 8064.258224] 7e60: b6de2894 b6f50810 000247b8 b2f75848 b2f19df0 ae286c58 ae489000 b6224f27
[ 8064.266435] 7e80: 00000001 00000000 b2f303d8 b60ae000 00000000 000001e3 00000004 b6e01b3b
[ 8064.274646] 7ea0: ae287890 b6e1e69c 00000001 ae286c58 ae489000 00000000 00000002 00000001
[ 8064.282858] 7ec0: 00000006 00000132 b2f078ec b6e1e69c ae286b4c b6e01dfd b2f078f0 00000001
[ 8064.291070] 7ee0: b2f078d8 00000000 ae286c58 b2f19dcc ae2869c8 edc21100 ee9bce40 00000009
[ 8064.299283] 7f00: ae2869c8 ecf36000 ecf37f7c ecf37f18 c0134e00 bf536314 00021000 00000003
[ 8064.307494] 7f20: ee9bce40 00004000 ecf37f5c ecf37f38 c013f000 c00860fc 00002710 00000009
[ 8064.315706] 7f40: 00007530 00007530 ae2869c8 ecf36000 ecf37f6c ee9bce41 00000009 ee9bce40
[ 8064.323918] 7f60: 00007530 ae2869c8 ecf36000 00000000 ecf37fa4 ecf37f80 c0135060 c0134a1c
[ 8064.332129] 7f80: 00002710 b6e28b3c 00007530 00000036 c000fbc4 ecf36000 00000000 ecf37fa8
[ 8064.340341] 7fa0: c000fa20 c0135030 00002710 b6e28b3c 00000009 00007530 ae2869c8 b2f02d70
[ 8064.348553] 7fc0: 00002710 b6e28b3c 00007530 00000036 00000140 00003c00 00000320 00000004
[ 8064.356765] 7fe0: b6e1e808 ae2869b4 b6e0a67b b625f4d6 200f0030 00000009 6913410e 61400b00
[ 8064.364973] Backtrace:
[ 8064.367471] [<c00e1934>] (__get_page_tail) from [<bf532348>] (gckOS_MapUserMemory+0x804/0xac8 [galcore])
[ 8064.376990] r5:ffeee448 r4:ee6c78b8
[ 8064.380654] [<bf531b44>] (gckOS_MapUserMemory [galcore]) from [<bf539c98>] (gckKERNEL_Dispatch+0xbb4/0x11ac [galcore])
[ 8064.391393] r10:00000000 r9:00000000 r8:ffffffff r7:00000001 r6:ed2a4e00 r5:ecf37db0
[ 8064.399299] r4:00000000
[ 8064.401908] [<bf5390e4>] (gckKERNEL_Dispatch [galcore]) from [<bf536428>] (drv_ioctl+0x120/0x28c [galcore])
[ 8064.411689] r9:ecf36000 r8:ecf37d90 r7:00007530 r6:c5ab1680 r5:ee04be00 r4:ecf36000
[ 8064.419540] [<bf536308>] (drv_ioctl [galcore]) from [<c0134e00>] (do_vfs_ioctl+0x3f0/0x614)
[ 8064.427925] r9:ecf36000 r8:ae2869c8 r7:00000009 r6:ee9bce40 r5:edc21100 r4:ae2869c8
[ 8064.435748] [<c0134a10>] (do_vfs_ioctl) from [<c0135060>] (SyS_ioctl+0x3c/0x64)
[ 8064.443084] r10:00000000 r9:ecf36000 r8:ae2869c8 r7:00007530 r6:ee9bce40 r5:00000009
[ 8064.450989] r4:ee9bce41
[ 8064.453546] [<c0135024>] (SyS_ioctl) from [<c000fa20>] (ret_fast_syscall+0x0/0x34)
[ 8064.461146] r9:ecf36000 r8:c000fbc4 r7:00000036 r6:00007530 r5:b6e28b3c r4:00002710
[ 8064.468967] Code: e5903014 e3130001 12433001 01a03000 (e5932004)
[ 8064.475171] ---[ end trace b26cc92b34d64366 ]---
How can I get rid of the memcpy in my code? Thanks.
Hi Phil,
I see that you mentioned that with memcpy you have the rotation working as
expected, so I presume we can safely rule out any setup related issues. I
suspect that you are facing synchronization issues with the bo leading up to the
error. When bo pointer is passed directly to GC320, is it ensured that this bo
is not queued for subsequent frame rendering. Normally this synchronization is
taken care by the display and GBM framework, with additional pipeline this needs
to be handled explicitly. To reduce the scope of the problem could you run a
test with a single offscreen buffer to rule out synchronization issues. Setup
something like below
- create an omap bo
- create egl image out of this bo
- setup this egl image as fbo
- render some color into this fbo
- pass it to gc320
- wait for gc320 to complete operation on this bo
- render next frame into this bo
On another note, do you need access to both rotated and unrotated output. If
not, you could achieve rotation through GL itself avoiding the need for another
processing stage.
Thanks,
Gowtham