1 /*
2  *  Copyright (C) 2017-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "RenderBufferDMA.h"
10 
11 #include "ServiceBroker.h"
12 #include "utils/BufferObject.h"
13 #include "utils/EGLImage.h"
14 #include "utils/log.h"
15 #include "windowing/WinSystem.h"
16 #include "windowing/linux/WinSystemEGL.h"
17 
18 using namespace KODI;
19 using namespace RETRO;
20 
CRenderBufferDMA(CRenderContext & context,int fourcc)21 CRenderBufferDMA::CRenderBufferDMA(CRenderContext& context, int fourcc)
22   : m_context(context), m_fourcc(fourcc), m_bo(CBufferObject::GetBufferObject(false))
23 {
24   auto winSystemEGL =
25       dynamic_cast<KODI::WINDOWING::LINUX::CWinSystemEGL*>(CServiceBroker::GetWinSystem());
26 
27   if (winSystemEGL == nullptr)
28     throw std::runtime_error("dynamic_cast failed to cast to CWinSystemEGL. This is likely due to "
29                              "a build misconfiguration as DMA can only be used with EGL and "
30                              "specifically platforms that implement CWinSystemEGL");
31 
32   m_egl = std::make_unique<CEGLImage>(winSystemEGL->GetEGLDisplay());
33 
34   CLog::Log(LOGDEBUG, "CRenderBufferDMA: using BufferObject type: {}", m_bo->GetName());
35 }
36 
~CRenderBufferDMA()37 CRenderBufferDMA::~CRenderBufferDMA()
38 {
39   DeleteTexture();
40 }
41 
Allocate(AVPixelFormat format,unsigned int width,unsigned int height)42 bool CRenderBufferDMA::Allocate(AVPixelFormat format, unsigned int width, unsigned int height)
43 {
44   // Initialize IRenderBuffer
45   m_format = format;
46   m_width = width;
47   m_height = height;
48 
49   m_bo->CreateBufferObject(m_fourcc, m_width, m_height);
50 
51   return true;
52 }
53 
GetFrameSize() const54 size_t CRenderBufferDMA::GetFrameSize() const
55 {
56   return m_bo->GetStride() * m_height;
57 }
58 
GetMemory()59 uint8_t* CRenderBufferDMA::GetMemory()
60 {
61   m_bo->SyncStart();
62   return m_bo->GetMemory();
63 }
64 
ReleaseMemory()65 void CRenderBufferDMA::ReleaseMemory()
66 {
67   m_bo->ReleaseMemory();
68   m_bo->SyncEnd();
69 }
70 
CreateTexture()71 void CRenderBufferDMA::CreateTexture()
72 {
73   glGenTextures(1, &m_textureId);
74 
75   glBindTexture(m_textureTarget, m_textureId);
76 
77   glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
78   glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
79   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
80   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
81 
82   glBindTexture(m_textureTarget, 0);
83 }
84 
UploadTexture()85 bool CRenderBufferDMA::UploadTexture()
86 {
87   if (m_bo->GetFd() < 0)
88     return false;
89 
90   if (!glIsTexture(m_textureId))
91     CreateTexture();
92 
93   glBindTexture(m_textureTarget, m_textureId);
94 
95   std::array<CEGLImage::EglPlane, CEGLImage::MAX_NUM_PLANES> planes;
96 
97   planes[0].fd = m_bo->GetFd();
98   planes[0].offset = 0;
99   planes[0].pitch = m_bo->GetStride();
100   planes[0].modifier = m_bo->GetModifier();
101 
102   CEGLImage::EglAttrs attribs;
103 
104   attribs.width = m_width;
105   attribs.height = m_height;
106   attribs.format = m_fourcc;
107   attribs.planes = planes;
108 
109   if (m_egl->CreateImage(attribs))
110     m_egl->UploadImage(m_textureTarget);
111 
112   m_egl->DestroyImage();
113 
114   glBindTexture(m_textureTarget, 0);
115 
116   return true;
117 }
118 
DeleteTexture()119 void CRenderBufferDMA::DeleteTexture()
120 {
121   if (glIsTexture(m_textureId))
122     glDeleteTextures(1, &m_textureId);
123 
124   m_textureId = 0;
125 }
126