Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/drm/egl_gbm_backend.cpp
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Line(s) | |||||
42 | { | 42 | { | ||
43 | // Egl is always direct rendering | 43 | // Egl is always direct rendering | ||
44 | setIsDirectRendering(true); | 44 | setIsDirectRendering(true); | ||
45 | setSyncsToVBlank(true); | 45 | setSyncsToVBlank(true); | ||
46 | connect(m_backend, &DrmBackend::outputAdded, this, &EglGbmBackend::createOutput); | 46 | connect(m_backend, &DrmBackend::outputAdded, this, &EglGbmBackend::createOutput); | ||
47 | connect(m_backend, &DrmBackend::outputRemoved, this, | 47 | connect(m_backend, &DrmBackend::outputRemoved, this, | ||
48 | [this] (DrmOutput *output) { | 48 | [this] (DrmOutput *output) { | ||
49 | auto it = std::find_if(m_outputs.begin(), m_outputs.end(), | 49 | auto it = std::find_if(m_outputs.begin(), m_outputs.end(), | ||
50 | [output] (const Output &o) { | 50 | [output] (const EglGbmOutput &o) { | ||
51 | return o.output == output; | 51 | return o.output == output; | ||
52 | } | 52 | } | ||
53 | ); | 53 | ); | ||
54 | if (it == m_outputs.end()) { | 54 | if (it == m_outputs.end()) { | ||
55 | return; | 55 | return; | ||
56 | } | 56 | } | ||
57 | cleanupOutput(*it); | 57 | cleanupOutput(*it); | ||
58 | m_outputs.erase(it); | 58 | m_outputs.erase(it); | ||
Show All 9 Lines | |||||
68 | void EglGbmBackend::cleanupSurfaces() | 68 | void EglGbmBackend::cleanupSurfaces() | ||
69 | { | 69 | { | ||
70 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | 70 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | ||
71 | cleanupOutput(*it); | 71 | cleanupOutput(*it); | ||
72 | } | 72 | } | ||
73 | m_outputs.clear(); | 73 | m_outputs.clear(); | ||
74 | } | 74 | } | ||
75 | 75 | | |||
76 | void EglGbmBackend::cleanupOutput(const Output &o) | 76 | void EglGbmBackend::cleanupOutput(const EglGbmOutput &o) | ||
77 | { | 77 | { | ||
78 | o.output->releaseGbm(); | 78 | o.output->releaseGbm(); | ||
79 | 79 | | |||
80 | if (o.eglSurface != EGL_NO_SURFACE) { | 80 | if (o.eglSurface != EGL_NO_SURFACE) { | ||
81 | eglDestroySurface(eglDisplay(), o.eglSurface); | 81 | eglDestroySurface(eglDisplay(), o.eglSurface); | ||
82 | } | 82 | } | ||
83 | } | 83 | } | ||
84 | 84 | | |||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Line(s) | |||||
137 | { | 137 | { | ||
138 | initBufferConfigs(); | 138 | initBufferConfigs(); | ||
139 | 139 | | |||
140 | if (!createContext()) { | 140 | if (!createContext()) { | ||
141 | return false; | 141 | return false; | ||
142 | } | 142 | } | ||
143 | 143 | | |||
144 | const auto outputs = m_backend->outputs(); | 144 | const auto outputs = m_backend->outputs(); | ||
145 | for (DrmOutput *drmOutput: outputs) { | 145 | for (Output *drmOutput: outputs) { | ||
146 | createOutput(drmOutput); | 146 | createOutput(qobject_cast<DrmOutput*>(drmOutput)); | ||
graesslin: Does the class need a DrmOutput or could it be changed to operate on Output instead? | |||||
147 | } | 147 | } | ||
148 | if (m_outputs.isEmpty()) { | 148 | if (m_outputs.isEmpty()) { | ||
149 | qCCritical(KWIN_DRM) << "Create Window Surfaces failed"; | 149 | qCCritical(KWIN_DRM) << "Create Window Surfaces failed"; | ||
150 | return false; | 150 | return false; | ||
151 | } | 151 | } | ||
152 | // set our first surface as the one for the abstract backend, just to make it happy | 152 | // set our first surface as the one for the abstract backend, just to make it happy | ||
153 | setSurface(m_outputs.first().eglSurface); | 153 | setSurface(m_outputs.first().eglSurface); | ||
154 | 154 | | |||
155 | return makeContextCurrent(m_outputs.first()); | 155 | return makeContextCurrent(m_outputs.first()); | ||
156 | } | 156 | } | ||
157 | 157 | | |||
158 | void EglGbmBackend::initRemotePresent() | 158 | void EglGbmBackend::initRemotePresent() | ||
159 | { | 159 | { | ||
160 | if (qEnvironmentVariableIsSet("KWIN_NO_REMOTE")) { | 160 | if (qEnvironmentVariableIsSet("KWIN_NO_REMOTE")) { | ||
161 | return; | 161 | return; | ||
162 | } | 162 | } | ||
163 | 163 | | |||
164 | qCDebug(KWIN_DRM) << "Support for remote access enabled"; | 164 | qCDebug(KWIN_DRM) << "Support for remote access enabled"; | ||
165 | m_remoteaccessManager.reset(new RemoteAccessManager); | 165 | m_remoteaccessManager.reset(new RemoteAccessManager); | ||
166 | } | 166 | } | ||
167 | 167 | | |||
168 | bool EglGbmBackend::resetOutput(Output &o, DrmOutput *drmOutput) | 168 | bool EglGbmBackend::resetOutput(EglGbmOutput &o, DrmOutput *drmOutput) | ||
169 | { | 169 | { | ||
170 | o.output = drmOutput; | 170 | o.output = drmOutput; | ||
171 | auto size = drmOutput->pixelSize(); | 171 | auto size = drmOutput->pixelSize(); | ||
172 | 172 | | |||
173 | auto gbmSurface = std::make_shared<GbmSurface>(m_backend->gbmDevice(), size.width(), size.height(), | 173 | auto gbmSurface = std::make_shared<GbmSurface>(m_backend->gbmDevice(), size.width(), size.height(), | ||
174 | GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); | 174 | GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); | ||
175 | if (!gbmSurface) { | 175 | if (!gbmSurface) { | ||
176 | qCCritical(KWIN_DRM) << "Create gbm surface failed"; | 176 | qCCritical(KWIN_DRM) << "Create gbm surface failed"; | ||
Show All 14 Lines | 183 | } else { | |||
191 | o.eglSurface = eglSurface; | 191 | o.eglSurface = eglSurface; | ||
192 | o.gbmSurface = gbmSurface; | 192 | o.gbmSurface = gbmSurface; | ||
193 | } | 193 | } | ||
194 | return true; | 194 | return true; | ||
195 | } | 195 | } | ||
196 | 196 | | |||
197 | void EglGbmBackend::createOutput(DrmOutput *drmOutput) | 197 | void EglGbmBackend::createOutput(DrmOutput *drmOutput) | ||
198 | { | 198 | { | ||
199 | Output o; | 199 | EglGbmOutput o; | ||
200 | if (resetOutput(o, drmOutput)) { | 200 | if (resetOutput(o, drmOutput)) { | ||
201 | connect(drmOutput, &DrmOutput::modeChanged, this, | 201 | connect(drmOutput, &DrmOutput::modeChanged, this, | ||
202 | [drmOutput, this] { | 202 | [drmOutput, this] { | ||
203 | auto it = std::find_if(m_outputs.begin(), m_outputs.end(), | 203 | auto it = std::find_if(m_outputs.begin(), m_outputs.end(), | ||
204 | [drmOutput] (const auto &o) { | 204 | [drmOutput] (const auto &o) { | ||
205 | return o.output == drmOutput; | 205 | return o.output == drmOutput; | ||
206 | } | 206 | } | ||
207 | ); | 207 | ); | ||
208 | if (it == m_outputs.end()) { | 208 | if (it == m_outputs.end()) { | ||
209 | return; | 209 | return; | ||
210 | } | 210 | } | ||
211 | resetOutput(*it, drmOutput); | 211 | resetOutput(*it, drmOutput); | ||
212 | } | 212 | } | ||
213 | ); | 213 | ); | ||
214 | m_outputs << o; | 214 | m_outputs << o; | ||
215 | } | 215 | } | ||
216 | } | 216 | } | ||
217 | 217 | | |||
218 | bool EglGbmBackend::makeContextCurrent(const Output &output) | 218 | bool EglGbmBackend::makeContextCurrent(const EglGbmOutput &output) | ||
219 | { | 219 | { | ||
220 | const EGLSurface surface = output.eglSurface; | 220 | const EGLSurface surface = output.eglSurface; | ||
221 | if (surface == EGL_NO_SURFACE) { | 221 | if (surface == EGL_NO_SURFACE) { | ||
222 | return false; | 222 | return false; | ||
223 | } | 223 | } | ||
224 | if (eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_FALSE) { | 224 | if (eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_FALSE) { | ||
225 | qCCritical(KWIN_DRM) << "Make Context Current failed"; | 225 | qCCritical(KWIN_DRM) << "Make Context Current failed"; | ||
226 | return false; | 226 | return false; | ||
Show All 26 Lines | 248 | const EGLint config_attribs[] = { | |||
253 | EGL_ALPHA_SIZE, 0, | 253 | EGL_ALPHA_SIZE, 0, | ||
254 | EGL_RENDERABLE_TYPE, isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, | 254 | EGL_RENDERABLE_TYPE, isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, | ||
255 | EGL_CONFIG_CAVEAT, EGL_NONE, | 255 | EGL_CONFIG_CAVEAT, EGL_NONE, | ||
256 | EGL_NONE, | 256 | EGL_NONE, | ||
257 | }; | 257 | }; | ||
258 | 258 | | |||
259 | EGLint count; | 259 | EGLint count; | ||
260 | EGLConfig configs[1024]; | 260 | EGLConfig configs[1024]; | ||
261 | if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1, &count) == EGL_FALSE) { | 261 | if (!eglChooseConfig(eglDisplay(), config_attribs, configs, sizeof(configs)/sizeof(EGLConfig), &count)) { | ||
262 | qCCritical(KWIN_DRM) << "choose config failed"; | 262 | qCCritical(KWIN_DRM) << "choose config failed"; | ||
263 | return false; | 263 | return false; | ||
264 | } | 264 | } | ||
265 | if (count != 1) { | 265 | | ||
266 | qCCritical(KWIN_DRM) << "choose config did not return a config" << count; | 266 | qCDebug(KWIN_DRM) << "EGL buffer configs count:" << count; | ||
267 | return false; | 267 | | ||
268 | // loop through all configs, chosing the first one that has suitable format | ||||
269 | for (EGLint i = 0; i < count; i++) { | ||||
270 | EGLint gbmFormat; | ||||
271 | // query some configuration parameters, to show in debug log | ||||
272 | eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat); | ||||
273 | | ||||
274 | if (KWIN_DRM().isDebugEnabled()) { | ||||
275 | // GBM formats are declared as FOURCC code (integer from ASCII chars, so use this fact) | ||||
276 | char gbmFormatStr[sizeof(EGLint) + 1] = {0}; | ||||
277 | memcpy(gbmFormatStr, &gbmFormat, sizeof(EGLint)); | ||||
278 | // query number of bits for color channel | ||||
279 | EGLint blueSize, redSize, greenSize, alphaSize; | ||||
280 | eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &redSize); | ||||
281 | eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &greenSize); | ||||
282 | eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blueSize); | ||||
283 | eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &alphaSize); | ||||
284 | qCDebug(KWIN_DRM) << " EGL config #" << i << " has GBM FOURCC format:" << gbmFormatStr | ||||
285 | << "; color sizes (RGBA order):" << redSize << greenSize << blueSize << alphaSize; | ||||
268 | } | 286 | } | ||
269 | setConfig(configs[0]); | | |||
270 | 287 | | |||
288 | if ((gbmFormat == GBM_FORMAT_XRGB8888) || (gbmFormat == GBM_FORMAT_ARGB8888)) { | ||||
289 | setConfig(configs[i]); | ||||
271 | return true; | 290 | return true; | ||
272 | } | 291 | } | ||
292 | } | ||||
293 | | ||||
294 | qCCritical(KWIN_DRM) << "choose EGL config did not return a suitable config" << count; | ||||
295 | return false; | ||||
296 | } | ||||
273 | 297 | | |||
274 | void EglGbmBackend::present() | 298 | void EglGbmBackend::present() | ||
275 | { | 299 | { | ||
276 | for (auto &o: m_outputs) { | 300 | for (auto &o: m_outputs) { | ||
277 | makeContextCurrent(o); | 301 | makeContextCurrent(o); | ||
278 | presentOnOutput(o); | 302 | presentOnOutput(o); | ||
279 | } | 303 | } | ||
280 | } | 304 | } | ||
281 | 305 | | |||
282 | void EglGbmBackend::presentOnOutput(EglGbmBackend::Output &o) | 306 | void EglGbmBackend::presentOnOutput(EglGbmBackend::EglGbmOutput &o) | ||
283 | { | 307 | { | ||
284 | eglSwapBuffers(eglDisplay(), o.eglSurface); | 308 | eglSwapBuffers(eglDisplay(), o.eglSurface); | ||
285 | o.buffer = m_backend->createBuffer(o.gbmSurface); | 309 | o.buffer = m_backend->createBuffer(o.gbmSurface); | ||
286 | if(m_remoteaccessManager && gbm_surface_has_free_buffers(o.gbmSurface->surface())) { | 310 | if(m_remoteaccessManager && gbm_surface_has_free_buffers(o.gbmSurface->surface())) { | ||
287 | // GBM surface is released on page flip so | 311 | // GBM surface is released on page flip so | ||
288 | // we should pass the buffer before it's presented | 312 | // we should pass the buffer before it's presented | ||
289 | m_remoteaccessManager->passBuffer(o.output, o.buffer); | 313 | m_remoteaccessManager->passBuffer(o.output, o.buffer); | ||
290 | } | 314 | } | ||
Show All 19 Lines | |||||
310 | QRegion EglGbmBackend::prepareRenderingFrame() | 334 | QRegion EglGbmBackend::prepareRenderingFrame() | ||
311 | { | 335 | { | ||
312 | startRenderTimer(); | 336 | startRenderTimer(); | ||
313 | return QRegion(); | 337 | return QRegion(); | ||
314 | } | 338 | } | ||
315 | 339 | | |||
316 | QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) | 340 | QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) | ||
317 | { | 341 | { | ||
318 | const Output &o = m_outputs.at(screenId); | 342 | const EglGbmOutput &o = m_outputs.at(screenId); | ||
319 | makeContextCurrent(o); | 343 | makeContextCurrent(o); | ||
320 | if (supportsBufferAge()) { | 344 | if (supportsBufferAge()) { | ||
321 | QRegion region; | 345 | QRegion region; | ||
322 | 346 | | |||
323 | // Note: An age of zero means the buffer contents are undefined | 347 | // Note: An age of zero means the buffer contents are undefined | ||
324 | if (o.bufferAge > 0 && o.bufferAge <= o.damageHistory.count()) { | 348 | if (o.bufferAge > 0 && o.bufferAge <= o.damageHistory.count()) { | ||
325 | for (int i = 0; i < o.bufferAge - 1; i++) | 349 | for (int i = 0; i < o.bufferAge - 1; i++) | ||
326 | region |= o.damageHistory[i]; | 350 | region |= o.damageHistory[i]; | ||
Show All 9 Lines | |||||
336 | void EglGbmBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) | 360 | void EglGbmBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) | ||
337 | { | 361 | { | ||
338 | Q_UNUSED(renderedRegion) | 362 | Q_UNUSED(renderedRegion) | ||
339 | Q_UNUSED(damagedRegion) | 363 | Q_UNUSED(damagedRegion) | ||
340 | } | 364 | } | ||
341 | 365 | | |||
342 | void EglGbmBackend::endRenderingFrameForScreen(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) | 366 | void EglGbmBackend::endRenderingFrameForScreen(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) | ||
343 | { | 367 | { | ||
344 | Output &o = m_outputs[screenId]; | 368 | EglGbmOutput &o = m_outputs[screenId]; | ||
345 | if (damagedRegion.intersected(o.output->geometry()).isEmpty() && screenId == 0) { | 369 | if (damagedRegion.intersected(o.output->geometry()).isEmpty() && screenId == 0) { | ||
346 | 370 | | |||
347 | // If the damaged region of a window is fully occluded, the only | 371 | // If the damaged region of a window is fully occluded, the only | ||
348 | // rendering done, if any, will have been to repair a reused back | 372 | // rendering done, if any, will have been to repair a reused back | ||
349 | // buffer, making it identical to the front buffer. | 373 | // buffer, making it identical to the front buffer. | ||
350 | // | 374 | // | ||
351 | // In this case we won't post the back buffer. Instead we'll just | 375 | // In this case we won't post the back buffer. Instead we'll just | ||
352 | // set the buffer age to 1, so the repaired regions won't be | 376 | // set the buffer age to 1, so the repaired regions won't be | ||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |
Does the class need a DrmOutput or could it be changed to operate on Output instead?