backends/drm: implement damage tracking for multi gpu transfers

Doesn't seem to help on my system, but maybe it helps with different drivers
This commit is contained in:
Xaver Hugl 2024-08-19 18:58:14 +02:00
parent 36c447a35a
commit 8a5f469f95
3 changed files with 23 additions and 15 deletions

View file

@ -57,7 +57,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::doBeginFrame()
m_scanoutBuffer.reset(); m_scanoutBuffer.reset();
m_colorPipeline = ColorPipeline{}; m_colorPipeline = ColorPipeline{};
return m_surface.startRendering(targetRect().size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(m_type), m_pipeline->output()->scanoutColorDescription(), return m_surface.startRendering(targetRect().size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(m_type), m_pipeline->output()->scanoutColorDescription(),
m_pipeline->output()->needsChannelFactorFallback() ? m_pipeline->output()->effectiveChannelFactors() : QVector3D(1, 1, 1), m_pipeline->iccProfile()); m_pipeline->output()->needsChannelFactorFallback() ? m_pipeline->output()->effectiveChannelFactors() : QVector3D(1, 1, 1), m_pipeline->iccProfile(), m_pipeline->output()->scale());
} }
bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame)

View file

@ -74,7 +74,7 @@ void EglGbmLayerSurface::destroyResources()
m_oldSurface = {}; m_oldSurface = {};
} }
std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile) std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile, double scale)
{ {
if (!checkSurface(bufferSize, formats)) { if (!checkSurface(bufferSize, formats)) {
return std::nullopt; return std::nullopt;
@ -94,6 +94,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
} }
slot->framebuffer()->colorAttachment()->setContentTransform(transformation); slot->framebuffer()->colorAttachment()->setContentTransform(transformation);
m_surface->currentSlot = slot; m_surface->currentSlot = slot;
m_surface->scale = scale;
if (m_surface->targetColorDescription != colorDescription || m_surface->channelFactors != channelFactors || m_surface->iccProfile != iccProfile) { if (m_surface->targetColorDescription != colorDescription || m_surface->channelFactors != channelFactors || m_surface->iccProfile != iccProfile) {
m_surface->damageJournal.clear(); m_surface->damageJournal.clear();
@ -225,7 +226,7 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion, OutputFrame
glFinish(); glFinish();
} }
m_surface->gbmSwapchain->release(m_surface->currentSlot, sourceFence.fileDescriptor().duplicate()); m_surface->gbmSwapchain->release(m_surface->currentSlot, sourceFence.fileDescriptor().duplicate());
const auto buffer = importBuffer(m_surface.get(), m_surface->currentSlot.get(), sourceFence.takeFileDescriptor(), frame); const auto buffer = importBuffer(m_surface.get(), m_surface->currentSlot.get(), sourceFence.takeFileDescriptor(), frame, damagedRegion);
if (buffer) { if (buffer) {
m_surface->currentFramebuffer = buffer; m_surface->currentFramebuffer = buffer;
return true; return true;
@ -517,7 +518,7 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::doRenderTestBuffer(Surface *
if (!slot) { if (!slot) {
return nullptr; return nullptr;
} }
if (const auto ret = importBuffer(surface, slot.get(), FileDescriptor{}, nullptr)) { if (const auto ret = importBuffer(surface, slot.get(), FileDescriptor{}, nullptr, infiniteRegion())) {
surface->currentSlot = slot; surface->currentSlot = slot;
surface->currentFramebuffer = ret; surface->currentFramebuffer = ret;
return ret; return ret;
@ -526,12 +527,12 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::doRenderTestBuffer(Surface *
} }
} }
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importBuffer(Surface *surface, EglSwapchainSlot *slot, FileDescriptor &&readFence, OutputFrame *frame) const std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importBuffer(Surface *surface, EglSwapchainSlot *slot, FileDescriptor &&readFence, OutputFrame *frame, const QRegion &damagedRegion) const
{ {
if (surface->bufferTarget == BufferTarget::Dumb || surface->importMode == MultiGpuImportMode::DumbBuffer) { if (surface->bufferTarget == BufferTarget::Dumb || surface->importMode == MultiGpuImportMode::DumbBuffer) {
return importWithCpu(surface, slot, frame); return importWithCpu(surface, slot, frame);
} else if (surface->importMode == MultiGpuImportMode::Egl) { } else if (surface->importMode == MultiGpuImportMode::Egl) {
return importWithEgl(surface, slot->buffer(), std::move(readFence), frame); return importWithEgl(surface, slot->buffer(), std::move(readFence), frame, damagedRegion);
} else { } else {
const auto ret = m_gpu->importBuffer(slot->buffer(), std::move(readFence)); const auto ret = m_gpu->importBuffer(slot->buffer(), std::move(readFence));
if (!ret) { if (!ret) {
@ -541,7 +542,7 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importBuffer(Surface *surfac
} }
} }
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame) const std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame, const QRegion &damagedRegion) const
{ {
Q_ASSERT(surface->importGbmSwapchain); Q_ASSERT(surface->importGbmSwapchain);
@ -579,9 +580,15 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surfa
return nullptr; return nullptr;
} }
QRegion deviceDamage;
for (const QRect &logical : damagedRegion) {
deviceDamage |= scaledRect(logical, surface->scale).toAlignedRect();
}
const QRegion repaint = deviceDamage | surface->importDamageJournal.accumulate(slot->age(), infiniteRegion());
surface->importDamageJournal.add(deviceDamage);
GLFramebuffer *fbo = slot->framebuffer(); GLFramebuffer *fbo = slot->framebuffer();
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle()); surface->importContext->pushFramebuffer(fbo);
glViewport(0, 0, fbo->size().width(), fbo->size().height());
const auto shader = surface->importContext->shaderManager()->pushShader(sourceTexture->target() == GL_TEXTURE_EXTERNAL_OES ? ShaderTrait::MapExternalTexture : ShaderTrait::MapTexture); const auto shader = surface->importContext->shaderManager()->pushShader(sourceTexture->target() == GL_TEXTURE_EXTERNAL_OES ? ShaderTrait::MapExternalTexture : ShaderTrait::MapTexture);
QMatrix4x4 mat; QMatrix4x4 mat;
@ -590,11 +597,10 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surfa
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mat); shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mat);
sourceTexture->bind(); sourceTexture->bind();
sourceTexture->render(fbo->size()); sourceTexture->render(repaint, fbo->size(), true);
sourceTexture->unbind(); sourceTexture->unbind();
glBindFramebuffer(GL_FRAMEBUFFER, 0); surface->importContext->popFramebuffer();
surface->importContext->shaderManager()->popShader(); surface->importContext->shaderManager()->popShader();
glFlush(); glFlush();
EGLNativeFence endFence(display); EGLNativeFence endFence(display);

View file

@ -56,7 +56,7 @@ public:
EglGbmLayerSurface(DrmGpu *gpu, EglGbmBackend *eglBackend, BufferTarget target = BufferTarget::Normal, FormatOption formatOption = FormatOption::PreferAlpha); EglGbmLayerSurface(DrmGpu *gpu, EglGbmBackend *eglBackend, BufferTarget target = BufferTarget::Normal, FormatOption formatOption = FormatOption::PreferAlpha);
~EglGbmLayerSurface(); ~EglGbmLayerSurface();
std::optional<OutputLayerBeginFrameInfo> startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile); std::optional<OutputLayerBeginFrameInfo> startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile, double scale);
bool endRendering(const QRegion &damagedRegion, OutputFrame *frame); bool endRendering(const QRegion &damagedRegion, OutputFrame *frame);
bool doesSurfaceFit(const QSize &size, const QHash<uint32_t, QList<uint64_t>> &formats) const; bool doesSurfaceFit(const QSize &size, const QHash<uint32_t, QList<uint64_t>> &formats) const;
@ -91,8 +91,10 @@ private:
QHash<GraphicsBuffer *, std::shared_ptr<GLTexture>> importedTextureCache; QHash<GraphicsBuffer *, std::shared_ptr<GLTexture>> importedTextureCache;
QImage cpuCopyCache; QImage cpuCopyCache;
MultiGpuImportMode importMode; MultiGpuImportMode importMode;
DamageJournal importDamageJournal;
std::shared_ptr<DrmFramebuffer> currentFramebuffer; std::shared_ptr<DrmFramebuffer> currentFramebuffer;
BufferTarget bufferTarget; BufferTarget bufferTarget;
double scale = 1;
// for color management // for color management
bool needsShadowBuffer = false; bool needsShadowBuffer = false;
@ -114,8 +116,8 @@ private:
std::shared_ptr<EglSwapchain> createGbmSwapchain(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QList<uint64_t> &modifiers, MultiGpuImportMode importMode, BufferTarget bufferTarget) const; std::shared_ptr<EglSwapchain> createGbmSwapchain(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QList<uint64_t> &modifiers, MultiGpuImportMode importMode, BufferTarget bufferTarget) const;
std::shared_ptr<DrmFramebuffer> doRenderTestBuffer(Surface *surface) const; std::shared_ptr<DrmFramebuffer> doRenderTestBuffer(Surface *surface) const;
std::shared_ptr<DrmFramebuffer> importBuffer(Surface *surface, EglSwapchainSlot *source, FileDescriptor &&readFence, OutputFrame *frame) const; std::shared_ptr<DrmFramebuffer> importBuffer(Surface *surface, EglSwapchainSlot *source, FileDescriptor &&readFence, OutputFrame *frame, const QRegion &damagedRegion) const;
std::shared_ptr<DrmFramebuffer> importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame) const; std::shared_ptr<DrmFramebuffer> importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame, const QRegion &damagedRegion) const;
std::shared_ptr<DrmFramebuffer> importWithCpu(Surface *surface, EglSwapchainSlot *source, OutputFrame *frame) const; std::shared_ptr<DrmFramebuffer> importWithCpu(Surface *surface, EglSwapchainSlot *source, OutputFrame *frame) const;
std::unique_ptr<Surface> m_surface; std::unique_ptr<Surface> m_surface;