Changeset View
Standalone View
plugins/platforms/drm/egl_gbm_backend.cpp
Show First 20 Lines • Show All 432 Lines • ▼ Show 20 Line(s) | |||||
433 | } | 433 | } | ||
434 | 434 | | |||
435 | void EglGbmBackend::present() | 435 | void EglGbmBackend::present() | ||
436 | { | 436 | { | ||
437 | Q_UNREACHABLE(); | 437 | Q_UNREACHABLE(); | ||
438 | // Not in use. This backend does per-screen rendering. | 438 | // Not in use. This backend does per-screen rendering. | ||
439 | } | 439 | } | ||
440 | 440 | | |||
441 | static QVector<EGLint> regionToRects(const QRegion ®ion, int height) | ||||
zzag: s/lastRegion/region/ | |||||
The region is in the global screen coordinates, but the buffer damage needs to be in the output local coordinates. zzag: The region is in the global screen coordinates, but the buffer damage needs to be in the output… | |||||
zzag: whitespace before `*` | |||||
442 | { | ||||
443 | QVector<EGLint> rects; | ||||
444 | rects.reserve(region.rectCount() * 4); | ||||
It would be nice to map rects from the global coordinate space to the output coordinate space and scale them both at the same time to avoid an extra for loop and save a couple of memory allocations. zzag: It would be nice to map rects from the global coordinate space to the output coordinate space… | |||||
zzag: No auto please. | |||||
445 | for (const auto &rect : region) { | ||||
446 | rects << rect.left(); | ||||
447 | rects << height - (rect.y() + rect.height()); | ||||
I suggest to use (rect.y() + rect.height()) instead of rect.bottom() + 1 because QRect::bottom() deviates from the true bottom border. QRect::right() and QRect::bottom() are good when you need to snap the right or the bottom border of one rectangle to another, e.g. rect.moveRight(anotherRect.right()); otherwise, it is better to stick with x() + width() and y() + height() to avoid off by one errors. zzag: I suggest to use (rect.y() + rect.height()) instead of rect.bottom() + 1 because QRect::bottom… | |||||
448 | rects << rect.width(); | ||||
449 | rects << rect.height(); | ||||
450 | } | ||||
451 | return rects; | ||||
452 | } | ||||
453 | | ||||
454 | void EglGbmBackend::aboutToStartPainting(const QRegion &damagedRegion) | ||||
455 | { | ||||
456 | // See EglGbmBackend::endRenderingFrameForScreen comment for the reason why we only support screenId=0 | ||||
457 | if (m_outputs.count() > 1) | ||||
458 | return; | ||||
459 | | ||||
460 | const Output &output = m_outputs.at(0); | ||||
461 | if (output.bufferAge > 0 | ||||
462 | && !damagedRegion.isEmpty() | ||||
463 | && supportsPartialUpdate()) | ||||
464 | { | ||||
465 | const QRegion region = (output.pendingDamagedRegions() | damagedRegion) | ||||
damagedRegion contains the region that will be repainted in the next frame, so we don't need to accumulate surface damages again. I suppose we want something like const QRegion region = damagedRegion & output.output->geometry(); zzag: `damagedRegion` contains the region that will be repainted in the next frame, so we don't need… | |||||
zzag: This comment hasn't been addressed. | |||||
466 | & output.output->geometry(); | ||||
467 | QVector<EGLint> rects = regionToRects(region, | ||||
468 | output.output->geometry().height()); | ||||
According to the spec, eglSetDamageRegionKHR() handles the case where n_rects is 0, so we can drop rects.isEmpty() check and thus simplify code a bit more. zzag: According to the spec, eglSetDamageRegionKHR() handles the case where n_rects is 0, so we can… | |||||
469 | const bool correct = eglSetDamageRegionKHR(eglDisplay(), output.eglSurface, | ||||
470 | rects.data(), rects.count()/4); | ||||
471 | if (!correct) { | ||||
472 | qCWarning(KWIN_DRM) << "failed eglSetDamageRegionKHR" << eglGetError(); | ||||
Use categorized logging please. Also, it's not a critical error if eglSetDamageRegionKHR() fails. qCWarning(KWIN_DRM) would be a better choice. zzag: Use categorized logging please. Also, it's not a critical error if eglSetDamageRegionKHR()… | |||||
473 | } | ||||
474 | } | ||||
475 | } | ||||
476 | | ||||
441 | void EglGbmBackend::presentOnOutput(Output &output) | 477 | void EglGbmBackend::presentOnOutput(Output &output) | ||
442 | { | 478 | { | ||
479 | if (supportsSwapBuffersWithDamage()) { | ||||
480 | QVector<EGLint> rects = regionToRects(output.damageHistory.constFirst(), | ||||
481 | output.output->geometry().height()); | ||||
482 | eglSwapBuffersWithDamageEXT(eglDisplay(), output.eglSurface, | ||||
483 | rects.data(), rects.count()/4); | ||||
484 | } else { | ||||
443 | eglSwapBuffers(eglDisplay(), output.eglSurface); | 485 | eglSwapBuffers(eglDisplay(), output.eglSurface); | ||
486 | } | ||||
444 | output.buffer = m_backend->createBuffer(output.gbmSurface); | 487 | output.buffer = m_backend->createBuffer(output.gbmSurface); | ||
445 | 488 | | |||
446 | if(m_remoteaccessManager && gbm_surface_has_free_buffers(output.gbmSurface->surface())) { | 489 | if(m_remoteaccessManager && gbm_surface_has_free_buffers(output.gbmSurface->surface())) { | ||
447 | // GBM surface is released on page flip so | 490 | // GBM surface is released on page flip so | ||
448 | // we should pass the buffer before it's presented. | 491 | // we should pass the buffer before it's presented. | ||
449 | m_remoteaccessManager->passBuffer(output.output, output.buffer); | 492 | m_remoteaccessManager->passBuffer(output.output, output.buffer); | ||
450 | } | 493 | } | ||
451 | 494 | | |||
Show All 26 Lines | 520 | { | |||
478 | const QSize &overall = screens()->size(); | 521 | const QSize &overall = screens()->size(); | ||
479 | const QRect &v = output.output->geometry(); | 522 | const QRect &v = output.output->geometry(); | ||
480 | qreal scale = output.output->scale(); | 523 | qreal scale = output.output->scale(); | ||
481 | 524 | | |||
482 | glViewport(-v.x() * scale, (v.height() - overall.height() + v.y()) * scale, | 525 | glViewport(-v.x() * scale, (v.height() - overall.height() + v.y()) * scale, | ||
483 | overall.width() * scale, overall.height() * scale); | 526 | overall.width() * scale, overall.height() * scale); | ||
484 | } | 527 | } | ||
485 | 528 | | |||
529 | QRegion EglGbmBackend::Output::pendingDamagedRegions() const | ||||
530 | { | ||||
531 | QRegion region; | ||||
532 | // Note: An age of zero means the buffer contents are undefined | ||||
533 | if (bufferAge > 0 && bufferAge <= damageHistory.count()) { | ||||
534 | for (int i = 0; i < bufferAge - 1; i++) | ||||
535 | region |= damageHistory[i]; | ||||
536 | } else { | ||||
537 | region = output->geometry(); | ||||
538 | } | ||||
539 | | ||||
540 | return region; | ||||
541 | } | ||||
I think we can drop this method now since only EglGbmBackend::prepareRenderingForScreen() needs to accumulate damage. zzag: I think we can drop this method now since only EglGbmBackend::prepareRenderingForScreen() needs… | |||||
I think next person who reads the code will prefer to see it encapsulated. apol: I think next person who reads the code will prefer to see it encapsulated.
| |||||
Currently pendingDamageRegions() is used only in two places - aboutToStartPainting() and prepareRenderingForScreen(). There is no reason to accumulate surface damages _again_ in aboutToStartPainting(). After the second usage of pendingDamageRegions() is dropped, the introduction of pendingDamageRegions() will look unrelated. zzag: Currently pendingDamageRegions() is used only in two places - aboutToStartPainting() and… | |||||
542 | | ||||
486 | QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) | 543 | QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) | ||
487 | { | 544 | { | ||
488 | const Output &output = m_outputs.at(screenId); | 545 | const Output &output = m_outputs.at(screenId); | ||
489 | 546 | | |||
490 | makeContextCurrent(output); | 547 | makeContextCurrent(output); | ||
491 | prepareRenderFramebuffer(output); | 548 | prepareRenderFramebuffer(output); | ||
492 | setViewport(output); | 549 | setViewport(output); | ||
493 | 550 | | |||
494 | if (supportsBufferAge()) { | 551 | if (supportsBufferAge()) { | ||
495 | QRegion region; | 552 | return output.pendingDamagedRegions(); | ||
496 | | ||||
497 | // Note: An age of zero means the buffer contents are undefined | | |||
498 | if (output.bufferAge > 0 && output.bufferAge <= output.damageHistory.count()) { | | |||
499 | for (int i = 0; i < output.bufferAge - 1; i++) | | |||
500 | region |= output.damageHistory[i]; | | |||
501 | } else { | | |||
502 | region = output.output->geometry(); | | |||
503 | } | | |||
504 | | ||||
505 | return region; | | |||
506 | } | 553 | } | ||
507 | return QRegion(); | 554 | return QRegion(); | ||
508 | } | 555 | } | ||
509 | 556 | | |||
510 | void EglGbmBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) | 557 | void EglGbmBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) | ||
511 | { | 558 | { | ||
This is the region in the buffer which must be repaired, i.e. the damage from the previous frames. Shouldn't we also include the current damage region? zzag: This is the region in the buffer which must be repaired, i.e. the damage from the previous… | |||||
512 | Q_UNUSED(renderedRegion) | 559 | Q_UNUSED(renderedRegion) | ||
513 | Q_UNUSED(damagedRegion) | 560 | Q_UNUSED(damagedRegion) | ||
514 | } | 561 | } | ||
zzag: IIRC, it is okay to set n_rects to 0 so we probably can drop this check. | |||||
515 | 562 | | |||
516 | void EglGbmBackend::endRenderingFrameForScreen(int screenId, | 563 | void EglGbmBackend::endRenderingFrameForScreen(int screenId, | ||
517 | const QRegion &renderedRegion, | 564 | const QRegion &renderedRegion, | ||
518 | const QRegion &damagedRegion) | 565 | const QRegion &damagedRegion) | ||
519 | { | 566 | { | ||
520 | Output &output = m_outputs[screenId]; | 567 | Output &output = m_outputs[screenId]; | ||
521 | renderFramebufferToSurface(output); | 568 | renderFramebufferToSurface(output); | ||
522 | 569 | | |||
▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines |
s/lastRegion/region/