Changeset View
Standalone View
plugins/platforms/drm/egl_gbm_backend.cpp
Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Line(s) | |||||
49 | 49 | | |||
50 | EglGbmBackend::~EglGbmBackend() | 50 | EglGbmBackend::~EglGbmBackend() | ||
51 | { | 51 | { | ||
52 | cleanup(); | 52 | cleanup(); | ||
53 | } | 53 | } | ||
54 | 54 | | |||
55 | void EglGbmBackend::cleanupSurfaces() | 55 | void EglGbmBackend::cleanupSurfaces() | ||
56 | { | 56 | { | ||
57 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | 57 | for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { | ||
58 | cleanupOutput(*it); | 58 | cleanupOutput(*it); | ||
59 | } | 59 | } | ||
60 | m_outputs.clear(); | 60 | m_outputs.clear(); | ||
61 | } | 61 | } | ||
62 | 62 | | |||
63 | void EglGbmBackend::cleanupOutput(const Output &output) | 63 | void EglGbmBackend::cleanupFramebuffer(Output &output) | ||
64 | { | 64 | { | ||
65 | if (!output.render.framebuffer) { | ||||
66 | return; | ||||
67 | } | ||||
68 | glDeleteTextures(1, &output.render.texture); | ||||
69 | output.render.texture = 0; | ||||
70 | glDeleteFramebuffers(1, &output.render.framebuffer); | ||||
71 | output.render.framebuffer = 0; | ||||
72 | } | ||||
romangg: Remove empty line | |||||
73 | | ||||
74 | void EglGbmBackend::cleanupOutput(Output &output) | ||||
75 | { | ||||
76 | cleanupFramebuffer(output); | ||||
65 | output.output->releaseGbm(); | 77 | output.output->releaseGbm(); | ||
66 | 78 | | |||
67 | if (output.eglSurface != EGL_NO_SURFACE) { | 79 | if (output.eglSurface != EGL_NO_SURFACE) { | ||
68 | eglDestroySurface(eglDisplay(), output.eglSurface); | 80 | eglDestroySurface(eglDisplay(), output.eglSurface); | ||
69 | } | 81 | } | ||
70 | } | 82 | } | ||
71 | 83 | | |||
72 | bool EglGbmBackend::initializeEgl() | 84 | bool EglGbmBackend::initializeEgl() | ||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Line(s) | 187 | if (eglSurface == EGL_NO_SURFACE) { | |||
177 | return EGL_NO_SURFACE; | 189 | return EGL_NO_SURFACE; | ||
178 | } | 190 | } | ||
179 | return eglSurface; | 191 | return eglSurface; | ||
180 | } | 192 | } | ||
181 | 193 | | |||
182 | bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput) | 194 | bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput) | ||
183 | { | 195 | { | ||
184 | output.output = drmOutput; | 196 | output.output = drmOutput; | ||
185 | const QSize size = drmOutput->pixelSize(); | 197 | const QSize size = drmOutput->hardwareTransforms() ? drmOutput->pixelSize() : | ||
198 | drmOutput->modeSize(); | ||||
186 | 199 | | |||
187 | auto gbmSurface = createGbmSurface(size); | 200 | auto gbmSurface = createGbmSurface(size); | ||
188 | if (!gbmSurface) { | 201 | if (!gbmSurface) { | ||
189 | return false; | 202 | return false; | ||
190 | } | 203 | } | ||
191 | auto eglSurface = createEglSurface(gbmSurface); | 204 | auto eglSurface = createEglSurface(gbmSurface); | ||
192 | if (eglSurface == EGL_NO_SURFACE) { | 205 | if (eglSurface == EGL_NO_SURFACE) { | ||
193 | return false; | 206 | return false; | ||
194 | } | 207 | } | ||
195 | 208 | | |||
196 | // destroy previous surface | 209 | // destroy previous surface | ||
197 | if (output.eglSurface != EGL_NO_SURFACE) { | 210 | if (output.eglSurface != EGL_NO_SURFACE) { | ||
198 | if (surface() == output.eglSurface) { | 211 | if (surface() == output.eglSurface) { | ||
199 | setSurface(eglSurface); | 212 | setSurface(eglSurface); | ||
200 | } | 213 | } | ||
201 | eglDestroySurface(eglDisplay(), output.eglSurface); | 214 | eglDestroySurface(eglDisplay(), output.eglSurface); | ||
202 | } | 215 | } | ||
203 | output.eglSurface = eglSurface; | 216 | output.eglSurface = eglSurface; | ||
204 | output.gbmSurface = gbmSurface; | 217 | output.gbmSurface = gbmSurface; | ||
218 | | ||||
219 | resetFramebuffer(output); | ||||
205 | return true; | 220 | return true; | ||
206 | } | 221 | } | ||
207 | 222 | | |||
208 | void EglGbmBackend::createOutput(DrmOutput *drmOutput) | 223 | void EglGbmBackend::createOutput(DrmOutput *drmOutput) | ||
209 | { | 224 | { | ||
210 | Output newOutput; | 225 | Output newOutput; | ||
211 | if (resetOutput(newOutput, drmOutput)) { | 226 | if (resetOutput(newOutput, drmOutput)) { | ||
212 | connect(drmOutput, &DrmOutput::modeChanged, this, | 227 | connect(drmOutput, &DrmOutput::modeChanged, this, | ||
Show All 22 Lines | 245 | { | |||
235 | ); | 250 | ); | ||
236 | if (it == m_outputs.end()) { | 251 | if (it == m_outputs.end()) { | ||
237 | return; | 252 | return; | ||
238 | } | 253 | } | ||
239 | cleanupOutput(*it); | 254 | cleanupOutput(*it); | ||
240 | m_outputs.erase(it); | 255 | m_outputs.erase(it); | ||
241 | } | 256 | } | ||
242 | 257 | | |||
258 | const char *vertexShader = R"SHADER( | ||||
259 | #version 130 | ||||
260 | uniform mat4 modelViewProjectionMatrix; | ||||
davidedmundson: seems unused?
Personally I'd say it's the better name. | |||||
I added this at some point because the GLShader and/or GLVertexBuffer classes were somewhat expecting a uniform variable of this name to be in the shader. But I don't remember if I also checked back one last time in the end without it. romangg: I added this at some point because the GLShader and/or GLVertexBuffer classes were somewhat… | |||||
261 | uniform mat4 rotationMatrix; | ||||
262 | | ||||
263 | in vec2 vertex; | ||||
264 | in vec2 texCoord; | ||||
265 | | ||||
266 | out vec2 TexCoord; | ||||
267 | | ||||
268 | void main() { | ||||
269 | gl_Position = rotationMatrix * vec4(vertex.x, vertex.y, 0.0, 1.0); | ||||
270 | TexCoord = texCoord; | ||||
271 | } | ||||
272 | )SHADER"; | ||||
273 | | ||||
274 | const char *fragmentShader = R"SHADER( | ||||
Can we make such GLSL assumptions? I expect this would error on the phone. ShaderManager::instance()->pushShader(ShaderTrait::MapTexture) would be safer. davidedmundson: Can we make such GLSL assumptions?
I expect this would error on the phone.
ShaderManager… | |||||
Yea, good question about the versioning. While working on it I just chose the one that worked on my system, but you're right these won't work on every system. Since the shader is pretty simple would it be enough to rewrite it as a version 110 shader to get it to work everywhere (although I then don't understand why most effects have a 110 an 140 version and not just the 110)? I didn't use the MapTexture trait because when doing that certain assumptions are being made about the shader that only fit shaders created for Scene rendering. romangg: Yea, good question about the versioning. While working on it I just chose the one that worked… | |||||
275 | #version 130 | ||||
276 | uniform sampler2D sampler; | ||||
277 | | ||||
278 | in vec2 TexCoord; | ||||
279 | out vec4 fragColor; | ||||
280 | | ||||
281 | void main() { | ||||
282 | fragColor = texture(sampler, TexCoord); | ||||
283 | } | ||||
284 | )SHADER"; | ||||
285 | | ||||
286 | const float vertices[] = { | ||||
287 | -1.0f, 1.0f, | ||||
288 | -1.0f, -1.0f, | ||||
289 | 1.0f, -1.0f, | ||||
290 | | ||||
291 | -1.0f, 1.0f, | ||||
292 | 1.0f, -1.0f, | ||||
293 | 1.0f, 1.0f, | ||||
romangg: Align indent. | |||||
294 | }; | ||||
295 | | ||||
296 | const float texCoords[] = { | ||||
297 | 0.0f, 1.0f, | ||||
298 | 0.0f, 0.0f, | ||||
299 | 1.0f, 0.0f, | ||||
300 | | ||||
301 | 0.0f, 1.0f, | ||||
302 | 1.0f, 0.0f, | ||||
303 | 1.0f, 1.0f | ||||
304 | }; | ||||
305 | | ||||
306 | bool EglGbmBackend::resetFramebuffer(Output &output) | ||||
307 | { | ||||
308 | cleanupFramebuffer(output); | ||||
309 | | ||||
310 | if (output.output->hardwareTransforms()) { | ||||
311 | // No need for an extra render target. | ||||
312 | return true; | ||||
313 | } | ||||
314 | | ||||
315 | makeContextCurrent(output); | ||||
316 | | ||||
317 | glGenFramebuffers(1, &output.render.framebuffer); | ||||
318 | glBindFramebuffer(GL_FRAMEBUFFER, output.render.framebuffer); | ||||
319 | GLRenderTarget::setKWinFramebuffer(output.render.framebuffer); | ||||
320 | | ||||
321 | glGenTextures(1, &output.render.texture); | ||||
322 | glBindTexture(GL_TEXTURE_2D, output.render.texture); | ||||
323 | | ||||
324 | const QSize texSize = output.output->pixelSize(); | ||||
325 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize.width(), texSize.height(), | ||||
326 | 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); | ||||
327 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); | ||||
328 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||
329 | | ||||
330 | glBindTexture(GL_TEXTURE_2D, 0); | ||||
331 | | ||||
332 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | ||||
333 | output.render.texture, 0); | ||||
334 | | ||||
335 | if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||||
336 | qCWarning(KWIN_DRM) << "Error: framebuffer not complete"; | ||||
337 | return false; | ||||
338 | } | ||||
339 | | ||||
340 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||||
341 | GLRenderTarget::setKWinFramebuffer(0); | ||||
342 | return true; | ||||
343 | } | ||||
344 | | ||||
345 | bool EglGbmBackend::initRenderTarget(Output &output) | ||||
346 | { | ||||
347 | if (output.render.shader) { | ||||
348 | // Already initialized. | ||||
349 | return true; | ||||
350 | } | ||||
351 | std::shared_ptr<GLShader> shader(ShaderManager::instance()->loadShaderFromCode(vertexShader, | ||||
352 | fragmentShader)); | ||||
353 | if (!shader) { | ||||
354 | qCWarning(KWIN_DRM) << "Error creating render shader."; | ||||
355 | return false; | ||||
356 | } | ||||
357 | | ||||
358 | output.render.shader = shader; | ||||
359 | | ||||
360 | std::shared_ptr<GLVertexBuffer> vbo(new GLVertexBuffer(KWin::GLVertexBuffer::Static)); | ||||
361 | vbo->setData(6, 2, vertices, texCoords); | ||||
362 | output.render.vbo = vbo; | ||||
363 | return true; | ||||
364 | } | ||||
365 | | ||||
366 | void EglGbmBackend::renderFramebufferToSurface(Output &output) | ||||
367 | { | ||||
368 | if (!output.render.framebuffer) { | ||||
369 | // No additional render target. | ||||
370 | return; | ||||
371 | } | ||||
372 | if (!initRenderTarget(output)) { | ||||
373 | return; | ||||
374 | } | ||||
375 | | ||||
376 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||||
377 | GLRenderTarget::setKWinFramebuffer(0); | ||||
378 | | ||||
379 | const auto size = output.output->modeSize(); | ||||
380 | glViewport(0, 0, size.width(), size.height()); | ||||
381 | | ||||
382 | ShaderBinder binder(output.render.shader.get()); | ||||
383 | QMatrix4x4 rotationMatrix; | ||||
384 | rotationMatrix.rotate(output.output->rotation(), 0, 0, 1); | ||||
385 | output.render.shader->setUniform("rotationMatrix", rotationMatrix); | ||||
386 | | ||||
387 | glBindTexture(GL_TEXTURE_2D, output.render.texture); | ||||
388 | output.render.vbo->render(GL_TRIANGLES); | ||||
389 | } | ||||
390 | | ||||
391 | void EglGbmBackend::prepareRenderFramebuffer(const Output &output) const | ||||
392 | { | ||||
393 | // When render.framebuffer is 0 we may just reset to the screen framebuffer. | ||||
394 | glBindFramebuffer(GL_FRAMEBUFFER, output.render.framebuffer); | ||||
395 | GLRenderTarget::setKWinFramebuffer(output.render.framebuffer); | ||||
396 | } | ||||
397 | | ||||
243 | bool EglGbmBackend::makeContextCurrent(const Output &output) const | 398 | bool EglGbmBackend::makeContextCurrent(const Output &output) const | ||
244 | { | 399 | { | ||
245 | const EGLSurface surface = output.eglSurface; | 400 | const EGLSurface surface = output.eglSurface; | ||
246 | if (surface == EGL_NO_SURFACE) { | 401 | if (surface == EGL_NO_SURFACE) { | ||
247 | return false; | 402 | return false; | ||
248 | } | 403 | } | ||
249 | if (eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_FALSE) { | 404 | if (eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_FALSE) { | ||
250 | qCCritical(KWIN_DRM) << "Make Context Current failed"; | 405 | qCCritical(KWIN_DRM) << "Make Context Current failed"; | ||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Line(s) | 520 | glViewport(-v.x() * scale, (v.height() - overall.height() + v.y()) * scale, | |||
366 | overall.width() * scale, overall.height() * scale); | 521 | overall.width() * scale, overall.height() * scale); | ||
367 | } | 522 | } | ||
368 | 523 | | |||
369 | QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) | 524 | QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) | ||
370 | { | 525 | { | ||
371 | const Output &output = m_outputs.at(screenId); | 526 | const Output &output = m_outputs.at(screenId); | ||
372 | 527 | | |||
373 | makeContextCurrent(output); | 528 | makeContextCurrent(output); | ||
529 | prepareRenderFramebuffer(output); | ||||
374 | setViewport(output); | 530 | setViewport(output); | ||
375 | 531 | | |||
376 | if (supportsBufferAge()) { | 532 | if (supportsBufferAge()) { | ||
377 | QRegion region; | 533 | QRegion region; | ||
378 | 534 | | |||
379 | // Note: An age of zero means the buffer contents are undefined | 535 | // Note: An age of zero means the buffer contents are undefined | ||
380 | if (output.bufferAge > 0 && output.bufferAge <= output.damageHistory.count()) { | 536 | if (output.bufferAge > 0 && output.bufferAge <= output.damageHistory.count()) { | ||
381 | for (int i = 0; i < output.bufferAge - 1; i++) | 537 | for (int i = 0; i < output.bufferAge - 1; i++) | ||
Show All 13 Lines | 549 | { | |||
395 | Q_UNUSED(damagedRegion) | 551 | Q_UNUSED(damagedRegion) | ||
396 | } | 552 | } | ||
397 | 553 | | |||
398 | void EglGbmBackend::endRenderingFrameForScreen(int screenId, | 554 | void EglGbmBackend::endRenderingFrameForScreen(int screenId, | ||
399 | const QRegion &renderedRegion, | 555 | const QRegion &renderedRegion, | ||
400 | const QRegion &damagedRegion) | 556 | const QRegion &damagedRegion) | ||
401 | { | 557 | { | ||
402 | Output &output = m_outputs[screenId]; | 558 | Output &output = m_outputs[screenId]; | ||
559 | renderFramebufferToSurface(output); | ||||
403 | 560 | | |||
404 | if (damagedRegion.intersected(output.output->geometry()).isEmpty() && screenId == 0) { | 561 | if (damagedRegion.intersected(output.output->geometry()).isEmpty() && screenId == 0) { | ||
405 | 562 | | |||
406 | // If the damaged region of a window is fully occluded, the only | 563 | // If the damaged region of a window is fully occluded, the only | ||
407 | // rendering done, if any, will have been to repair a reused back | 564 | // rendering done, if any, will have been to repair a reused back | ||
408 | // buffer, making it identical to the front buffer. | 565 | // buffer, making it identical to the front buffer. | ||
409 | // | 566 | // | ||
410 | // In this case we won't post the back buffer. Instead we'll just | 567 | // In this case we won't post the back buffer. Instead we'll just | ||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |
Remove empty line