Changeset View
Changeset View
Standalone View
Standalone View
platformsupport/scenes/opengl/egl_dmabuf.cpp
- This file was moved from platformsupport/scenes/opengl/linux_dmabuf.cpp.
Show All 12 Lines | |||||
13 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. | ||
17 | 17 | | |||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | *********************************************************************/ | 20 | *********************************************************************/ | ||
21 | #include "linux_dmabuf.h" | 21 | #include "egl_dmabuf.h" | ||
22 | 22 | | |||
23 | #include "drm_fourcc.h" | 23 | #include "drm_fourcc.h" | ||
24 | #include "../../../wayland_server.h" | 24 | #include "../../../wayland_server.h" | ||
25 | 25 | | |||
26 | #include <KWayland/Server/display.h> | | |||
27 | | ||||
28 | #include <unistd.h> | 26 | #include <unistd.h> | ||
29 | #include <EGL/eglmesaext.h> | 27 | #include <EGL/eglmesaext.h> | ||
30 | 28 | | |||
31 | namespace KWin | 29 | namespace KWin | ||
32 | { | 30 | { | ||
33 | 31 | | |||
34 | typedef EGLBoolean (*eglQueryDmaBufFormatsEXT_func) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); | 32 | typedef EGLBoolean (*eglQueryDmaBufFormatsEXT_func) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); | ||
35 | typedef EGLBoolean (*eglQueryDmaBufModifiersEXT_func) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); | 33 | typedef EGLBoolean (*eglQueryDmaBufModifiersEXT_func) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); | ||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Line(s) | 165 | { | |||
168 | 1, 1, | 166 | 1, 1, | ||
169 | DRM_FORMAT_R8, | 167 | DRM_FORMAT_R8, | ||
170 | 2 | 168 | 2 | ||
171 | } | 169 | } | ||
172 | } | 170 | } | ||
173 | } | 171 | } | ||
174 | }; | 172 | }; | ||
175 | 173 | | |||
176 | DmabufBuffer::DmabufBuffer(EGLImage image, | 174 | EglDmabufBuffer::EglDmabufBuffer(EGLImage image, | ||
177 | const QVector<Plane> &planes, | 175 | const QVector<Plane> &planes, | ||
178 | uint32_t format, | 176 | uint32_t format, | ||
179 | const QSize &size, | 177 | const QSize &size, | ||
180 | Flags flags, | 178 | Flags flags, | ||
181 | LinuxDmabuf *interfaceImpl) | 179 | EglDmabuf *interfaceImpl) | ||
182 | : DmabufBuffer(planes, format, size, flags, interfaceImpl) | 180 | : EglDmabufBuffer(planes, format, size, flags, interfaceImpl) | ||
183 | { | 181 | { | ||
184 | m_importType = ImportType::Direct; | 182 | m_importType = ImportType::Direct; | ||
185 | addImage(image); | 183 | addImage(image); | ||
186 | } | 184 | } | ||
187 | 185 | | |||
188 | 186 | | |||
189 | DmabufBuffer::DmabufBuffer(const QVector<Plane> &planes, | 187 | EglDmabufBuffer::EglDmabufBuffer(const QVector<Plane> &planes, | ||
190 | uint32_t format, | 188 | uint32_t format, | ||
191 | const QSize &size, | 189 | const QSize &size, | ||
192 | Flags flags, | 190 | Flags flags, | ||
193 | LinuxDmabuf *interfaceImpl) | 191 | EglDmabuf *interfaceImpl) | ||
194 | : KWayland::Server::LinuxDmabufUnstableV1Buffer(format, size) | 192 | : DmabufBuffer(planes, format, size, flags) | ||
195 | , m_planes(planes) | | |||
196 | , m_flags(flags) | | |||
197 | , m_interfaceImpl(interfaceImpl) | 193 | , m_interfaceImpl(interfaceImpl) | ||
198 | { | 194 | { | ||
199 | m_importType = ImportType::Conversion; | 195 | m_importType = ImportType::Conversion; | ||
200 | } | 196 | } | ||
201 | 197 | | |||
202 | DmabufBuffer::~DmabufBuffer() | 198 | EglDmabufBuffer::~EglDmabufBuffer() | ||
203 | { | 199 | { | ||
204 | if (m_interfaceImpl) { | | |||
205 | m_interfaceImpl->removeBuffer(this); | | |||
206 | removeImages(); | 200 | removeImages(); | ||
207 | } | 201 | } | ||
208 | 202 | | |||
209 | // Close all open file descriptors | 203 | void EglDmabufBuffer::setInterfaceImplementation(EglDmabuf *interfaceImpl) | ||
210 | for (int i = 0; i < m_planes.count(); i++) { | 204 | { | ||
211 | if (m_planes[i].fd != -1) | 205 | m_interfaceImpl = interfaceImpl; | ||
212 | ::close(m_planes[i].fd); | | |||
213 | m_planes[i].fd = -1; | | |||
214 | } | | |||
215 | } | 206 | } | ||
216 | 207 | | |||
217 | void DmabufBuffer::addImage(EGLImage image) | 208 | void EglDmabufBuffer::addImage(EGLImage image) | ||
218 | { | 209 | { | ||
219 | m_images << image; | 210 | m_images << image; | ||
220 | } | 211 | } | ||
221 | 212 | | |||
222 | void DmabufBuffer::removeImages() | 213 | void EglDmabufBuffer::removeImages() | ||
223 | { | 214 | { | ||
224 | for (auto image : m_images) { | 215 | for (auto image : m_images) { | ||
225 | eglDestroyImageKHR(m_interfaceImpl->m_backend->eglDisplay(), image); | 216 | eglDestroyImageKHR(m_interfaceImpl->m_backend->eglDisplay(), image); | ||
226 | } | 217 | } | ||
227 | m_images.clear(); | 218 | m_images.clear(); | ||
228 | m_interfaceImpl = nullptr; | | |||
229 | } | 219 | } | ||
230 | 220 | | |||
231 | using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; | 221 | using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; | ||
232 | using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; | 222 | using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; | ||
233 | 223 | | |||
234 | EGLImage LinuxDmabuf::createImage(const QVector<Plane> &planes, | 224 | EGLImage EglDmabuf::createImage(const QVector<Plane> &planes, | ||
235 | uint32_t format, | 225 | uint32_t format, | ||
236 | const QSize &size) | 226 | const QSize &size) | ||
237 | { | 227 | { | ||
238 | const bool hasModifiers = eglQueryDmaBufModifiersEXT != nullptr && | 228 | const bool hasModifiers = eglQueryDmaBufModifiersEXT != nullptr && | ||
239 | planes[0].modifier != DRM_FORMAT_MOD_INVALID; | 229 | planes[0].modifier != DRM_FORMAT_MOD_INVALID; | ||
240 | 230 | | |||
241 | QVector<EGLint> attribs; | 231 | QVector<EGLint> attribs; | ||
242 | attribs << EGL_WIDTH << size.width() | 232 | attribs << EGL_WIDTH << size.width() | ||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Line(s) | 287 | EGLImage image = eglCreateImageKHR(m_backend->eglDisplay(), | |||
301 | attribs.data()); | 291 | attribs.data()); | ||
302 | if (image == EGL_NO_IMAGE_KHR) { | 292 | if (image == EGL_NO_IMAGE_KHR) { | ||
303 | return nullptr; | 293 | return nullptr; | ||
304 | } | 294 | } | ||
305 | 295 | | |||
306 | return image; | 296 | return image; | ||
307 | } | 297 | } | ||
308 | 298 | | |||
309 | KWayland::Server::LinuxDmabufUnstableV1Buffer* LinuxDmabuf::importBuffer(const QVector<Plane> &planes, | 299 | KWayland::Server::LinuxDmabufUnstableV1Buffer* EglDmabuf::importBuffer(const QVector<Plane> &planes, | ||
310 | uint32_t format, | 300 | uint32_t format, | ||
311 | const QSize &size, | 301 | const QSize &size, | ||
312 | Flags flags) | 302 | Flags flags) | ||
313 | { | 303 | { | ||
314 | Q_ASSERT(planes.count() > 0); | 304 | Q_ASSERT(planes.count() > 0); | ||
315 | 305 | | |||
316 | // Try first to import as a single image | 306 | // Try first to import as a single image | ||
317 | if (auto *img = createImage(planes, format, size)) { | 307 | if (auto *img = createImage(planes, format, size)) { | ||
318 | return new DmabufBuffer(img, planes, format, size, flags, this); | 308 | return new EglDmabufBuffer(img, planes, format, size, flags, this); | ||
319 | } | 309 | } | ||
320 | 310 | | |||
321 | // TODO: to enable this we must be able to store multiple textures per window pixmap | 311 | // TODO: to enable this we must be able to store multiple textures per window pixmap | ||
322 | // and when on window draw do yuv to rgb transformation per shader (see Weston) | 312 | // and when on window draw do yuv to rgb transformation per shader (see Weston) | ||
323 | // // not a single image, try yuv import | 313 | // // not a single image, try yuv import | ||
324 | // return yuvImport(planes, format, size, flags); | 314 | // return yuvImport(planes, format, size, flags); | ||
325 | 315 | | |||
326 | return nullptr; | 316 | return nullptr; | ||
327 | } | 317 | } | ||
328 | 318 | | |||
329 | KWayland::Server::LinuxDmabufUnstableV1Buffer* LinuxDmabuf::yuvImport(const QVector<Plane> &planes, | 319 | KWayland::Server::LinuxDmabufUnstableV1Buffer* EglDmabuf::yuvImport(const QVector<Plane> &planes, | ||
330 | uint32_t format, | 320 | uint32_t format, | ||
331 | const QSize &size, | 321 | const QSize &size, | ||
332 | Flags flags) | 322 | Flags flags) | ||
333 | { | 323 | { | ||
334 | YuvFormat yuvFormat; | 324 | YuvFormat yuvFormat; | ||
335 | for (YuvFormat f : yuvFormats) { | 325 | for (YuvFormat f : yuvFormats) { | ||
336 | if (f.format == format) { | 326 | if (f.format == format) { | ||
337 | yuvFormat = f; | 327 | yuvFormat = f; | ||
338 | break; | 328 | break; | ||
339 | } | 329 | } | ||
340 | } | 330 | } | ||
341 | if (yuvFormat.format == 0) { | 331 | if (yuvFormat.format == 0) { | ||
342 | return nullptr; | 332 | return nullptr; | ||
343 | } | 333 | } | ||
344 | if (planes.count() != yuvFormat.inputPlanes) { | 334 | if (planes.count() != yuvFormat.inputPlanes) { | ||
345 | return nullptr; | 335 | return nullptr; | ||
346 | } | 336 | } | ||
347 | 337 | | |||
348 | auto *buf = new DmabufBuffer(planes, format, size, flags, this); | 338 | auto *buf = new EglDmabufBuffer(planes, format, size, flags, this); | ||
349 | 339 | | |||
350 | for (int i = 0; i < yuvFormat.outputPlanes; i++) { | 340 | for (int i = 0; i < yuvFormat.outputPlanes; i++) { | ||
351 | int planeIndex = yuvFormat.planes[i].planeIndex; | 341 | int planeIndex = yuvFormat.planes[i].planeIndex; | ||
352 | Plane plane = { | 342 | Plane plane = { | ||
353 | planes[planeIndex].fd, | 343 | planes[planeIndex].fd, | ||
354 | planes[planeIndex].offset, | 344 | planes[planeIndex].offset, | ||
355 | planes[planeIndex].stride, | 345 | planes[planeIndex].stride, | ||
356 | planes[planeIndex].modifier | 346 | planes[planeIndex].modifier | ||
Show All 9 Lines | 354 | if (!image) { | |||
366 | return nullptr; | 356 | return nullptr; | ||
367 | } | 357 | } | ||
368 | buf->addImage(image); | 358 | buf->addImage(image); | ||
369 | } | 359 | } | ||
370 | // TODO: add buf import properties | 360 | // TODO: add buf import properties | ||
371 | return buf; | 361 | return buf; | ||
372 | } | 362 | } | ||
373 | 363 | | |||
374 | LinuxDmabuf* LinuxDmabuf::factory(AbstractEglBackend *backend) | 364 | EglDmabuf* EglDmabuf::factory(AbstractEglBackend *backend) | ||
375 | { | 365 | { | ||
376 | if (!backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import"))) { | 366 | if (!backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import"))) { | ||
377 | return nullptr; | 367 | return nullptr; | ||
378 | } | 368 | } | ||
379 | 369 | | |||
380 | if (backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) { | 370 | if (backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) { | ||
381 | eglQueryDmaBufFormatsEXT = (eglQueryDmaBufFormatsEXT_func) eglGetProcAddress("eglQueryDmaBufFormatsEXT"); | 371 | eglQueryDmaBufFormatsEXT = (eglQueryDmaBufFormatsEXT_func) eglGetProcAddress("eglQueryDmaBufFormatsEXT"); | ||
382 | eglQueryDmaBufModifiersEXT = (eglQueryDmaBufModifiersEXT_func) eglGetProcAddress("eglQueryDmaBufModifiersEXT"); | 372 | eglQueryDmaBufModifiersEXT = (eglQueryDmaBufModifiersEXT_func) eglGetProcAddress("eglQueryDmaBufModifiersEXT"); | ||
383 | } | 373 | } | ||
384 | 374 | | |||
385 | if (eglQueryDmaBufFormatsEXT == nullptr) { | 375 | if (eglQueryDmaBufFormatsEXT == nullptr) { | ||
386 | return nullptr; | 376 | return nullptr; | ||
387 | } | 377 | } | ||
388 | 378 | | |||
389 | return new LinuxDmabuf(backend); | 379 | return new EglDmabuf(backend); | ||
390 | } | 380 | } | ||
391 | 381 | | |||
392 | LinuxDmabuf::LinuxDmabuf(AbstractEglBackend *backend) | 382 | EglDmabuf::EglDmabuf(AbstractEglBackend *backend) | ||
393 | : KWayland::Server::LinuxDmabufUnstableV1Interface::Impl() | 383 | : LinuxDmabuf() | ||
394 | , m_backend(backend) | 384 | , m_backend(backend) | ||
395 | { | 385 | { | ||
396 | Q_ASSERT(waylandServer()); | 386 | auto prevBuffersSet = waylandServer()->linuxDmabufBuffers(); | ||
397 | m_interface = waylandServer()->display()->createLinuxDmabufInterface(backend); | 387 | for (auto *buffer : prevBuffersSet) { | ||
388 | auto *buf = static_cast<EglDmabufBuffer*>(buffer); | ||||
389 | buf->setInterfaceImplementation(this); | ||||
390 | buf->addImage(createImage(buf->planes(), buf->format(), buf->size())); | ||||
391 | } | ||||
398 | setSupportedFormatsAndModifiers(); | 392 | setSupportedFormatsAndModifiers(); | ||
399 | m_interface->setImpl(this); | | |||
400 | m_interface->create(); | | |||
401 | } | 393 | } | ||
402 | 394 | | |||
403 | LinuxDmabuf::~LinuxDmabuf() | 395 | EglDmabuf::~EglDmabuf() | ||
404 | { | 396 | { | ||
405 | for (auto *dmabuf : qAsConst(m_buffers)) { | 397 | auto curBuffers = waylandServer()->linuxDmabufBuffers(); | ||
406 | dmabuf->removeImages(); | 398 | for (auto *buffer : curBuffers) { | ||
399 | auto *buf = static_cast<EglDmabufBuffer*>(buffer); | ||||
400 | buf->removeImages(); | ||||
407 | } | 401 | } | ||
408 | } | 402 | } | ||
409 | 403 | | |||
410 | void LinuxDmabuf::removeBuffer(DmabufBuffer *buffer) | | |||
411 | { | | |||
412 | m_buffers.remove(buffer); | | |||
413 | } | | |||
414 | | ||||
415 | const uint32_t s_multiPlaneFormats[] = { | 404 | const uint32_t s_multiPlaneFormats[] = { | ||
416 | DRM_FORMAT_XRGB8888_A8, | 405 | DRM_FORMAT_XRGB8888_A8, | ||
417 | DRM_FORMAT_XBGR8888_A8, | 406 | DRM_FORMAT_XBGR8888_A8, | ||
418 | DRM_FORMAT_RGBX8888_A8, | 407 | DRM_FORMAT_RGBX8888_A8, | ||
419 | DRM_FORMAT_BGRX8888_A8, | 408 | DRM_FORMAT_BGRX8888_A8, | ||
420 | DRM_FORMAT_RGB888_A8, | 409 | DRM_FORMAT_RGB888_A8, | ||
421 | DRM_FORMAT_BGR888_A8, | 410 | DRM_FORMAT_BGR888_A8, | ||
422 | DRM_FORMAT_RGB565_A8, | 411 | DRM_FORMAT_RGB565_A8, | ||
Show All 29 Lines | 438 | if (*it == linuxFormat) { | |||
452 | it--; | 441 | it--; | ||
453 | break; | 442 | break; | ||
454 | } | 443 | } | ||
455 | } | 444 | } | ||
456 | it++; | 445 | it++; | ||
457 | } | 446 | } | ||
458 | } | 447 | } | ||
459 | 448 | | |||
460 | void LinuxDmabuf::setSupportedFormatsAndModifiers() | 449 | void EglDmabuf::setSupportedFormatsAndModifiers() | ||
461 | { | 450 | { | ||
462 | const EGLDisplay eglDisplay = m_backend->eglDisplay(); | 451 | const EGLDisplay eglDisplay = m_backend->eglDisplay(); | ||
463 | EGLint count = 0; | 452 | EGLint count = 0; | ||
464 | EGLBoolean success = eglQueryDmaBufFormatsEXT(eglDisplay, 0, nullptr, &count); | 453 | EGLBoolean success = eglQueryDmaBufFormatsEXT(eglDisplay, 0, nullptr, &count); | ||
465 | 454 | | |||
466 | if (!success || count == 0) { | 455 | if (!success || count == 0) { | ||
467 | return; | 456 | return; | ||
468 | } | 457 | } | ||
Show All 24 Lines | 475 | if (eglQueryDmaBufModifiersEXT(eglDisplay, | |||
493 | set.insert(format, modifiersSet); | 482 | set.insert(format, modifiersSet); | ||
494 | continue; | 483 | continue; | ||
495 | } | 484 | } | ||
496 | } | 485 | } | ||
497 | } | 486 | } | ||
498 | set.insert(format, QSet<uint64_t>()); | 487 | set.insert(format, QSet<uint64_t>()); | ||
499 | } | 488 | } | ||
500 | 489 | | |||
501 | m_interface->setSupportedFormatsWithModifiers(set); | 490 | LinuxDmabuf::setSupportedFormatsAndModifiers(set); | ||
502 | } | 491 | } | ||
503 | 492 | | |||
504 | } | 493 | } |