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