Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qiosurfacegraphicsbuffer.mm
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qdebug.h>
8#include <QtCore/qloggingcategory.h>
9
10#include <CoreGraphics/CoreGraphics.h>
11#include <IOSurface/IOSurface.h>
12
13// CGColorSpaceCopyPropertyList is available on 10.12 and above,
14// but was only added in the 10.14 SDK, so declare it just in case.
15extern "C" CFPropertyListRef CGColorSpaceCopyPropertyList(CGColorSpaceRef space);
16
18
19Q_LOGGING_CATEGORY(lcQpaIOSurface, "qt.qpa.backingstore.iosurface");
20
21QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format)
22 : QPlatformGraphicsBuffer(size, format)
23{
24 const size_t width = size.width();
25 const size_t height = size.height();
26
27 Q_ASSERT(width <= IOSurfaceGetPropertyMaximum(kIOSurfaceWidth));
28 Q_ASSERT(height <= IOSurfaceGetPropertyMaximum(kIOSurfaceHeight));
29
30 static const char bytesPerElement = 4;
31
32 const size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
33 const size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow);
34
35 NSDictionary *options = @{
36 (id)kIOSurfaceWidth: @(width),
37 (id)kIOSurfaceHeight: @(height),
38 (id)kIOSurfacePixelFormat: @(unsigned('BGRA')),
39 (id)kIOSurfaceBytesPerElement: @(bytesPerElement),
40 (id)kIOSurfaceBytesPerRow: @(bytesPerRow),
41 (id)kIOSurfaceAllocSize: @(totalBytes),
42 };
43
44 m_surface = IOSurfaceCreate((CFDictionaryRef)options);
45 Q_ASSERT(m_surface);
46
47 Q_ASSERT(size_t(bytesPerLine()) == bytesPerRow);
48 Q_ASSERT(size_t(byteCount()) == totalBytes);
49
50 QObject::connect(this, &QObject::objectNameChanged, this, [this]{
51 IOSurfaceSetValue(m_surface, kIOSurfaceName, objectName().toNSString());
52 });
53}
54
55QIOSurfaceGraphicsBuffer::~QIOSurfaceGraphicsBuffer()
56{
57}
58
59void QIOSurfaceGraphicsBuffer::setColorSpace(QCFType<CGColorSpaceRef> colorSpace)
60{
61 static const auto kIOSurfaceColorSpace = CFSTR("IOSurfaceColorSpace");
62
63 qCDebug(lcQpaIOSurface) << "Tagging" << this << "with color space" << colorSpace;
64
65 if (colorSpace) {
66 IOSurfaceSetValue(m_surface, kIOSurfaceColorSpace,
67 QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace)));
68 } else {
69 IOSurfaceRemoveValue(m_surface, kIOSurfaceColorSpace);
70 }
71}
72
73const uchar *QIOSurfaceGraphicsBuffer::data() const
74{
75 return (const uchar *)IOSurfaceGetBaseAddress(m_surface);
76}
77
78uchar *QIOSurfaceGraphicsBuffer::data()
79{
80 return (uchar *)IOSurfaceGetBaseAddress(m_surface);
81}
82
83int QIOSurfaceGraphicsBuffer::bytesPerLine() const
84{
85 return IOSurfaceGetBytesPerRow(m_surface);
86}
87
88IOSurfaceRef QIOSurfaceGraphicsBuffer::surface()
89{
90 return m_surface;
91}
92
93bool QIOSurfaceGraphicsBuffer::isInUse() const
94{
95 return IOSurfaceIsInUse(m_surface);
96}
97
98IOSurfaceLockOptions lockOptionsForAccess(QPlatformGraphicsBuffer::AccessTypes access)
99{
100 IOSurfaceLockOptions lockOptions = 0;
101 if (!(access & QPlatformGraphicsBuffer::SWWriteAccess))
102 lockOptions |= kIOSurfaceLockReadOnly;
103 return lockOptions;
104}
105
106bool QIOSurfaceGraphicsBuffer::doLock(AccessTypes access, const QRect &rect)
107{
108 Q_UNUSED(rect);
109 Q_ASSERT(!isLocked());
110
111 qCDebug(lcQpaIOSurface) << "Locking" << this << "for" << access;
112
113 // FIXME: Teach QPlatformBackingStore::composeAndFlush about non-2D texture
114 // targets, so that we can use CGLTexImageIOSurface2D to support TextureAccess.
115 if (access & (TextureAccess | HWCompositor))
116 return false;
117
118 auto lockOptions = lockOptionsForAccess(access);
119
120 // Try without read-back first
121 lockOptions |= kIOSurfaceLockAvoidSync;
122 kern_return_t ret = IOSurfaceLock(m_surface, lockOptions, nullptr);
123 if (ret == kIOSurfaceSuccess)
124 return true;
125
126 if (ret == kIOReturnCannotLock) {
127 qCWarning(lcQpaIOSurface) << "Locking of" << this << "requires read-back";
128 lockOptions ^= kIOSurfaceLockAvoidSync;
129 ret = IOSurfaceLock(m_surface, lockOptions, nullptr);
130 }
131
132 if (ret != kIOSurfaceSuccess) {
133 qCWarning(lcQpaIOSurface) << "Failed to lock" << this << ret;
134 return false;
135 }
136
137 return true;
138}
139
140void QIOSurfaceGraphicsBuffer::doUnlock()
141{
142 qCDebug(lcQpaIOSurface) << "Unlocking" << this << "from" << isLocked();
143
144 auto lockOptions = lockOptionsForAccess(isLocked());
145 bool success = IOSurfaceUnlock(m_surface, lockOptions, nullptr) == kIOSurfaceSuccess;
146 Q_ASSERT_X(success, "QIOSurfaceGraphicsBuffer", "Unlocking surface should succeed");
147}
148
149#ifndef QT_NO_DEBUG_STREAM
150QDebug operator<<(QDebug debug, const QIOSurfaceGraphicsBuffer *graphicsBuffer)
151{
152 QDebugStateSaver saver(debug);
153 debug.nospace();
154 debug << "QIOSurfaceGraphicsBuffer(" << (const void *)graphicsBuffer;
155 if (graphicsBuffer) {
156 debug << ", surface=" << graphicsBuffer->m_surface;
157 debug << ", size=" << graphicsBuffer->size();
158 debug << ", isLocked=" << bool(graphicsBuffer->isLocked());
159 debug << ", isInUse=" << graphicsBuffer->isInUse();
160 }
161 debug << ')';
162 return debug;
163}
164#endif // !QT_NO_DEBUG_STREAM
165
166QT_END_NAMESPACE
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
IOSurfaceLockOptions lockOptionsForAccess(QPlatformGraphicsBuffer::AccessTypes access)
QDebug operator<<(QDebug debug, const QIOSurfaceGraphicsBuffer *graphicsBuffer)