source: trunk/src/opengl/qgl_mac.mm@ 1028

Last change on this file since 1028 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 31.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qgl.h"
43
44// There are functions that are deprecated in 10.5, but really there's no way around them
45// for Carbon, so just undefine them.
46#undef DEPRECATED_ATTRIBUTE
47#define DEPRECATED_ATTRIBUTE
48#if defined(Q_WS_MAC)
49#ifndef QT_MAC_USE_COCOA
50#ifdef qDebug
51# undef qDebug
52# include <AGL/agl.h>
53# include <AGL/aglRenderers.h>
54# include <OpenGL/gl.h>
55# ifdef QT_NO_DEBUG
56# define qDebug qt_noop(),1?(void)0:qDebug
57# endif
58#else
59# include <AGL/agl.h>
60# include <AGL/aglRenderers.h>
61# include <OpenGL/gl.h>
62#endif
63#else
64#include <private/qcocoaview_mac_p.h>
65#endif
66
67
68#include <OpenGL/gl.h>
69#include <CoreServices/CoreServices.h>
70#include <private/qfont_p.h>
71#include <private/qfontengine_p.h>
72#include <private/qgl_p.h>
73#include <private/qpaintengine_opengl_p.h>
74#include <private/qt_mac_p.h>
75#include <qpixmap.h>
76#include <qtimer.h>
77#include <qapplication.h>
78#include <qstack.h>
79#include <qdesktopwidget.h>
80#include <qdebug.h>
81
82QT_BEGIN_NAMESPACE
83#ifdef QT_MAC_USE_COCOA
84QT_END_NAMESPACE
85
86QT_FORWARD_DECLARE_CLASS(QWidget)
87QT_FORWARD_DECLARE_CLASS(QWidgetPrivate)
88QT_FORWARD_DECLARE_CLASS(QGLWidgetPrivate)
89
90QT_BEGIN_NAMESPACE
91
92void *qt_current_nsopengl_context()
93{
94 return [NSOpenGLContext currentContext];
95}
96
97static GLint attribValue(NSOpenGLPixelFormat *fmt, NSOpenGLPixelFormatAttribute attrib)
98{
99 GLint res;
100 [fmt getValues:&res forAttribute:attrib forVirtualScreen:0];
101 return res;
102}
103
104static int def(int val, int defVal)
105{
106 return val != -1 ? val : defVal;
107}
108#else
109QRegion qt_mac_get_widget_rgn(const QWidget *widget);
110#endif
111
112extern quint32 *qt_mac_pixmap_get_base(const QPixmap *);
113extern int qt_mac_pixmap_get_bytes_per_line(const QPixmap *);
114extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
115extern void qt_mac_dispose_rgn(RgnHandle); //qregion_mac.cpp
116extern QRegion qt_mac_convert_mac_region(RgnHandle); //qregion_mac.cpp
117extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); //qglobal.cpp
118
119/*
120 QGLTemporaryContext implementation
121*/
122
123class QGLTemporaryContextPrivate
124{
125public:
126#ifndef QT_MAC_USE_COCOA
127 AGLContext ctx;
128#else
129 NSOpenGLContext *ctx;
130#endif
131};
132
133QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
134 : d(new QGLTemporaryContextPrivate)
135{
136 d->ctx = 0;
137#ifndef QT_MAC_USE_COCOA
138 GLint attribs[] = {AGL_RGBA, AGL_NONE};
139 AGLPixelFormat fmt = aglChoosePixelFormat(0, 0, attribs);
140 if (!fmt) {
141 qDebug("QGLTemporaryContext: Couldn't find any RGB visuals");
142 return;
143 }
144 d->ctx = aglCreateContext(fmt, 0);
145 if (!d->ctx)
146 qDebug("QGLTemporaryContext: Unable to create context");
147 else
148 aglSetCurrentContext(d->ctx);
149 aglDestroyPixelFormat(fmt);
150#else
151 QMacCocoaAutoReleasePool pool;
152 NSOpenGLPixelFormatAttribute attribs[] = { 0 };
153 NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
154 if (!fmt) {
155 qWarning("QGLTemporaryContext: Cannot find any visuals");
156 return;
157 }
158
159 d->ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
160 if (!d->ctx)
161 qWarning("QGLTemporaryContext: Cannot create context");
162 else
163 [d->ctx makeCurrentContext];
164 [fmt release];
165#endif
166}
167
168QGLTemporaryContext::~QGLTemporaryContext()
169{
170 if (d->ctx) {
171#ifndef QT_MAC_USE_COCOA
172 aglSetCurrentContext(0);
173 aglDestroyContext(d->ctx);
174#else
175 [NSOpenGLContext clearCurrentContext];
176 [d->ctx release];
177#endif
178 }
179}
180
181bool QGLFormat::hasOpenGL()
182{
183 return true;
184}
185
186bool QGLFormat::hasOpenGLOverlays()
187{
188 return false;
189}
190
191bool QGLContext::chooseContext(const QGLContext *shareContext)
192{
193 QMacCocoaAutoReleasePool pool;
194 Q_D(QGLContext);
195 d->cx = 0;
196 d->vi = chooseMacVisual(0);
197 if (!d->vi)
198 return false;
199
200#ifndef QT_MAC_USE_COCOA
201 AGLPixelFormat fmt = (AGLPixelFormat)d->vi;
202 GLint res;
203 aglDescribePixelFormat(fmt, AGL_LEVEL, &res);
204 d->glFormat.setPlane(res);
205 if (deviceIsPixmap())
206 res = 0;
207 else
208 aglDescribePixelFormat(fmt, AGL_DOUBLEBUFFER, &res);
209 d->glFormat.setDoubleBuffer(res);
210 aglDescribePixelFormat(fmt, AGL_DEPTH_SIZE, &res);
211 d->glFormat.setDepth(res);
212 if (d->glFormat.depth())
213 d->glFormat.setDepthBufferSize(res);
214 aglDescribePixelFormat(fmt, AGL_RGBA, &res);
215 d->glFormat.setRgba(res);
216 aglDescribePixelFormat(fmt, AGL_RED_SIZE, &res);
217 d->glFormat.setRedBufferSize(res);
218 aglDescribePixelFormat(fmt, AGL_GREEN_SIZE, &res);
219 d->glFormat.setGreenBufferSize(res);
220 aglDescribePixelFormat(fmt, AGL_BLUE_SIZE, &res);
221 d->glFormat.setBlueBufferSize(res);
222 aglDescribePixelFormat(fmt, AGL_ALPHA_SIZE, &res);
223 d->glFormat.setAlpha(res);
224 if (d->glFormat.alpha())
225 d->glFormat.setAlphaBufferSize(res);
226 aglDescribePixelFormat(fmt, AGL_ACCUM_RED_SIZE, &res);
227 // Bug in Apple OpenGL (rdr://5015603), when we don't have an accumulation
228 // buffer, it still claims that we have a 16-bit one (which is pretty rare).
229 // So, we just assume we can never have a buffer that small.
230 d->glFormat.setAccum(res > 5);
231 if (d->glFormat.accum())
232 d->glFormat.setAccumBufferSize(res);
233 aglDescribePixelFormat(fmt, AGL_STENCIL_SIZE, &res);
234 d->glFormat.setStencil(res);
235 if (d->glFormat.stencil())
236 d->glFormat.setStencilBufferSize(res);
237 aglDescribePixelFormat(fmt, AGL_STEREO, &res);
238 d->glFormat.setStereo(res);
239 aglDescribePixelFormat(fmt, AGL_SAMPLE_BUFFERS_ARB, &res);
240 d->glFormat.setSampleBuffers(res);
241 if (d->glFormat.sampleBuffers()) {
242 aglDescribePixelFormat(fmt, AGL_SAMPLES_ARB, &res);
243 d->glFormat.setSamples(res);
244 }
245#else
246 NSOpenGLPixelFormat *fmt = static_cast<NSOpenGLPixelFormat *>(d->vi);
247
248 d->glFormat = QGLFormat();
249
250 // ### make sure to reset other options
251 d->glFormat.setDoubleBuffer(attribValue(fmt, NSOpenGLPFADoubleBuffer));
252
253 int depthSize = attribValue(fmt, NSOpenGLPFADepthSize);
254 d->glFormat.setDepth(depthSize > 0);
255 if (depthSize > 0)
256 d->glFormat.setDepthBufferSize(depthSize);
257
258 int alphaSize = attribValue(fmt, NSOpenGLPFAAlphaSize);
259 d->glFormat.setAlpha(alphaSize > 0);
260 if (alphaSize > 0)
261 d->glFormat.setAlphaBufferSize(alphaSize);
262
263 int accumSize = attribValue(fmt, NSOpenGLPFAAccumSize);
264 d->glFormat.setAccum(accumSize > 0);
265 if (accumSize > 0)
266 d->glFormat.setAccumBufferSize(accumSize);
267
268 int stencilSize = attribValue(fmt, NSOpenGLPFAStencilSize);
269 d->glFormat.setStencil(stencilSize > 0);
270 if (stencilSize > 0)
271 d->glFormat.setStencilBufferSize(stencilSize);
272
273 d->glFormat.setStereo(attribValue(fmt, NSOpenGLPFAStereo));
274
275 int sampleBuffers = attribValue(fmt, NSOpenGLPFASampleBuffers);
276 d->glFormat.setSampleBuffers(sampleBuffers);
277 if (sampleBuffers > 0)
278 d->glFormat.setSamples(attribValue(fmt, NSOpenGLPFASamples));
279#endif
280 if (shareContext && (!shareContext->isValid() || !shareContext->d_func()->cx)) {
281 qWarning("QGLContext::chooseContext: Cannot share with invalid context");
282 shareContext = 0;
283 }
284
285 // sharing between rgba and color-index will give wrong colors
286 if (shareContext && (format().rgba() != shareContext->format().rgba()))
287 shareContext = 0;
288
289#ifndef QT_MAC_USE_COCOA
290 AGLContext ctx = aglCreateContext(fmt, (AGLContext) (shareContext ? shareContext->d_func()->cx : 0));
291#else
292 NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt
293 shareContext:(shareContext ? static_cast<NSOpenGLContext *>(shareContext->d_func()->cx)
294 : 0)];
295#endif
296 if (!ctx) {
297#ifndef QT_MAC_USE_COCOA
298 GLenum err = aglGetError();
299 if (err == AGL_BAD_MATCH || err == AGL_BAD_CONTEXT) {
300 if (shareContext && shareContext->d_func()->cx) {
301 qWarning("QGLContext::chooseContext(): Context sharing mismatch!");
302 if (!(ctx = aglCreateContext(fmt, 0)))
303 return false;
304 shareContext = 0;
305 }
306 }
307#else
308 if (shareContext) {
309 ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
310 if (ctx) {
311 qWarning("QGLContext::chooseContext: Context sharing mismatch");
312 shareContext = 0;
313 }
314 }
315#endif
316 if (!ctx) {
317 qWarning("QGLContext::chooseContext: Unable to create QGLContext");
318 return false;
319 }
320 }
321 d->cx = ctx;
322 if (shareContext && shareContext->d_func()->cx) {
323 QGLContext *share = const_cast<QGLContext *>(shareContext);
324 d->sharing = true;
325 share->d_func()->sharing = true;
326 }
327 if (deviceIsPixmap())
328 updatePaintDevice();
329
330 // vblank syncing
331 GLint interval = d->reqFormat.swapInterval();
332 if (interval != -1) {
333#ifndef QT_MAC_USE_COCOA
334 aglSetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
335 if (interval != 0)
336 aglEnable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
337 else
338 aglDisable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
339#else
340 [ctx setValues:&interval forParameter:NSOpenGLCPSwapInterval];
341#endif
342 }
343#ifndef QT_MAC_USE_COCOA
344 aglGetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
345#else
346 [ctx getValues:&interval forParameter:NSOpenGLCPSwapInterval];
347#endif
348 d->glFormat.setSwapInterval(interval);
349 return true;
350}
351
352void *QGLContextPrivate::tryFormat(const QGLFormat &format)
353{
354 static const int Max = 40;
355#ifndef QT_MAC_USE_COCOA
356 GLint attribs[Max], cnt = 0;
357 bool device_is_pixmap = (paintDevice->devType() == QInternal::Pixmap);
358
359 attribs[cnt++] = AGL_RGBA;
360 attribs[cnt++] = AGL_BUFFER_SIZE;
361 attribs[cnt++] = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
362 attribs[cnt++] = AGL_LEVEL;
363 attribs[cnt++] = format.plane();
364
365 if (format.redBufferSize() != -1) {
366 attribs[cnt++] = AGL_RED_SIZE;
367 attribs[cnt++] = format.redBufferSize();
368 }
369 if (format.greenBufferSize() != -1) {
370 attribs[cnt++] = AGL_GREEN_SIZE;
371 attribs[cnt++] = format.greenBufferSize();
372 }
373 if (format.blueBufferSize() != -1) {
374 attribs[cnt++] = AGL_BLUE_SIZE;
375 attribs[cnt++] = format.blueBufferSize();
376 }
377 if (device_is_pixmap) {
378 attribs[cnt++] = AGL_PIXEL_SIZE;
379 attribs[cnt++] = static_cast<QPixmap *>(paintDevice)->depth();
380 attribs[cnt++] = AGL_OFFSCREEN;
381 if (!format.alpha()) {
382 attribs[cnt++] = AGL_ALPHA_SIZE;
383 attribs[cnt++] = 8;
384 }
385 } else {
386 if (format.doubleBuffer())
387 attribs[cnt++] = AGL_DOUBLEBUFFER;
388 }
389
390 if (format.stereo())
391 attribs[cnt++] = AGL_STEREO;
392 if (format.alpha()) {
393 attribs[cnt++] = AGL_ALPHA_SIZE;
394 attribs[cnt++] = format.alphaBufferSize() == -1 ? 8 : format.alphaBufferSize();
395 }
396 if (format.stencil()) {
397 attribs[cnt++] = AGL_STENCIL_SIZE;
398 attribs[cnt++] = format.stencilBufferSize() == -1 ? 8 : format.stencilBufferSize();
399 }
400 if (format.depth()) {
401 attribs[cnt++] = AGL_DEPTH_SIZE;
402 attribs[cnt++] = format.depthBufferSize() == -1 ? 32 : format.depthBufferSize();
403 }
404 if (format.accum()) {
405 attribs[cnt++] = AGL_ACCUM_RED_SIZE;
406 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
407 attribs[cnt++] = AGL_ACCUM_BLUE_SIZE;
408 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
409 attribs[cnt++] = AGL_ACCUM_GREEN_SIZE;
410 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
411 attribs[cnt++] = AGL_ACCUM_ALPHA_SIZE;
412 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
413 }
414 if (format.sampleBuffers()) {
415 attribs[cnt++] = AGL_SAMPLE_BUFFERS_ARB;
416 attribs[cnt++] = 1;
417 attribs[cnt++] = AGL_SAMPLES_ARB;
418 attribs[cnt++] = format.samples() == -1 ? 4 : format.samples();
419 }
420
421 attribs[cnt] = AGL_NONE;
422 Q_ASSERT(cnt < Max);
423 return aglChoosePixelFormat(0, 0, attribs);
424#else
425 NSOpenGLPixelFormatAttribute attribs[Max];
426 int cnt = 0;
427 int devType = paintDevice->devType();
428 bool device_is_pixmap = (devType == QInternal::Pixmap);
429 int depth = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
430
431 attribs[cnt++] = NSOpenGLPFAColorSize;
432 attribs[cnt++] = depth;
433
434 if (device_is_pixmap) {
435 attribs[cnt++] = NSOpenGLPFAOffScreen;
436 } else {
437 if (format.doubleBuffer())
438 attribs[cnt++] = NSOpenGLPFADoubleBuffer;
439 }
440 if (glFormat.stereo())
441 attribs[cnt++] = NSOpenGLPFAStereo;
442 if (device_is_pixmap || format.alpha()) {
443 attribs[cnt++] = NSOpenGLPFAAlphaSize;
444 attribs[cnt++] = def(format.alphaBufferSize(), 8);
445 }
446 if (format.stencil()) {
447 attribs[cnt++] = NSOpenGLPFAStencilSize;
448 attribs[cnt++] = def(format.stencilBufferSize(), 8);
449 }
450 if (format.depth()) {
451 attribs[cnt++] = NSOpenGLPFADepthSize;
452 attribs[cnt++] = def(format.depthBufferSize(), 32);
453 }
454 if (format.accum()) {
455 attribs[cnt++] = NSOpenGLPFAAccumSize;
456 attribs[cnt++] = def(format.accumBufferSize(), 1);
457 }
458 if (format.sampleBuffers()) {
459 attribs[cnt++] = NSOpenGLPFASampleBuffers;
460 attribs[cnt++] = 1;
461 attribs[cnt++] = NSOpenGLPFASamples;
462 attribs[cnt++] = def(format.samples(), 4);
463 }
464
465 if (format.directRendering())
466 attribs[cnt++] = NSOpenGLPFAAccelerated;
467
468 if (devType == QInternal::Pbuffer)
469 attribs[cnt++] = NSOpenGLPFAPixelBuffer;
470
471 attribs[cnt] = 0;
472 Q_ASSERT(cnt < Max);
473 return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
474#endif
475}
476