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

Last change on this file since 345 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 30.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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
119bool QGLFormat::hasOpenGL()
120{
121 return true;
122}
123
124bool QGLFormat::hasOpenGLOverlays()
125{
126 return false;
127}
128
129bool QGLContext::chooseContext(const QGLContext *shareContext)
130{
131 QMacCocoaAutoReleasePool pool;
132 Q_D(QGLContext);
133 d->cx = 0;
134 d->vi = chooseMacVisual(0);
135 if (!d->vi)
136 return false;
137
138#ifndef QT_MAC_USE_COCOA
139 AGLPixelFormat fmt = (AGLPixelFormat)d->vi;
140 GLint res;
141 aglDescribePixelFormat(fmt, AGL_LEVEL, &res);
142 d->glFormat.setPlane(res);
143 if (deviceIsPixmap())
144 res = 0;
145 else
146 aglDescribePixelFormat(fmt, AGL_DOUBLEBUFFER, &res);
147 d->glFormat.setDoubleBuffer(res);
148 aglDescribePixelFormat(fmt, AGL_DEPTH_SIZE, &res);
149 d->glFormat.setDepth(res);
150 if (d->glFormat.depth())
151 d->glFormat.setDepthBufferSize(res);
152 aglDescribePixelFormat(fmt, AGL_RGBA, &res);
153 d->glFormat.setRgba(res);
154 aglDescribePixelFormat(fmt, AGL_RED_SIZE, &res);
155 d->glFormat.setRedBufferSize(res);
156 aglDescribePixelFormat(fmt, AGL_GREEN_SIZE, &res);
157 d->glFormat.setGreenBufferSize(res);
158 aglDescribePixelFormat(fmt, AGL_BLUE_SIZE, &res);
159 d->glFormat.setBlueBufferSize(res);
160 aglDescribePixelFormat(fmt, AGL_ALPHA_SIZE, &res);
161 d->glFormat.setAlpha(res);
162 if (d->glFormat.alpha())
163 d->glFormat.setAlphaBufferSize(res);
164 aglDescribePixelFormat(fmt, AGL_ACCUM_RED_SIZE, &res);
165 // Bug in Apple OpenGL (rdr://5015603), when we don't have an accumulation
166 // buffer, it still claims that we have a 16-bit one (which is pretty rare).
167 // So, we just assume we can never have a buffer that small.
168 d->glFormat.setAccum(res > 5);
169 if (d->glFormat.accum())
170 d->glFormat.setAccumBufferSize(res);
171 aglDescribePixelFormat(fmt, AGL_STENCIL_SIZE, &res);
172 d->glFormat.setStencil(res);
173 if (d->glFormat.stencil())
174 d->glFormat.setStencilBufferSize(res);
175 aglDescribePixelFormat(fmt, AGL_STEREO, &res);
176 d->glFormat.setStereo(res);
177 aglDescribePixelFormat(fmt, AGL_SAMPLE_BUFFERS_ARB, &res);
178 d->glFormat.setSampleBuffers(res);
179 if (d->glFormat.sampleBuffers()) {
180 aglDescribePixelFormat(fmt, AGL_SAMPLES_ARB, &res);
181 d->glFormat.setSamples(res);
182 }
183#else
184 NSOpenGLPixelFormat *fmt = static_cast<NSOpenGLPixelFormat *>(d->vi);
185
186 d->glFormat = QGLFormat();
187
188 // ### make sure to reset other options
189 d->glFormat.setDoubleBuffer(attribValue(fmt, NSOpenGLPFADoubleBuffer));
190
191 int depthSize = attribValue(fmt, NSOpenGLPFADepthSize);
192 d->glFormat.setDepth(depthSize > 0);
193 if (depthSize > 0)
194 d->glFormat.setDepthBufferSize(depthSize);
195
196 int alphaSize = attribValue(fmt, NSOpenGLPFAAlphaSize);
197 d->glFormat.setAlpha(alphaSize > 0);
198 if (alphaSize > 0)
199 d->glFormat.setAlphaBufferSize(alphaSize);
200
201 int accumSize = attribValue(fmt, NSOpenGLPFAAccumSize);
202 d->glFormat.setAccum(accumSize > 0);
203 if (accumSize > 0)
204 d->glFormat.setAccumBufferSize(accumSize);
205
206 int stencilSize = attribValue(fmt, NSOpenGLPFAStencilSize);
207 d->glFormat.setStencil(stencilSize > 0);
208 if (stencilSize > 0)
209 d->glFormat.setStencilBufferSize(stencilSize);
210
211 d->glFormat.setStereo(attribValue(fmt, NSOpenGLPFAStereo));
212
213 int sampleBuffers = attribValue(fmt, NSOpenGLPFASampleBuffers);
214 d->glFormat.setSampleBuffers(sampleBuffers);
215 if (sampleBuffers > 0)
216 d->glFormat.setSamples(attribValue(fmt, NSOpenGLPFASamples));
217#endif
218 if (shareContext && (!shareContext->isValid() || !shareContext->d_func()->cx)) {
219 qWarning("QGLContext::chooseContext: Cannot share with invalid context");
220 shareContext = 0;
221 }
222
223 // sharing between rgba and color-index will give wrong colors
224 if (shareContext && (format().rgba() != shareContext->format().rgba()))
225 shareContext = 0;
226
227#ifndef QT_MAC_USE_COCOA
228 AGLContext ctx = aglCreateContext(fmt, (AGLContext) (shareContext ? shareContext->d_func()->cx : 0));
229#else
230 NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt
231 shareContext:(shareContext ? static_cast<NSOpenGLContext *>(shareContext->d_func()->cx)
232 : 0)];
233#endif
234 if (!ctx) {
235#ifndef QT_MAC_USE_COCOA
236 GLenum err = aglGetError();
237 if (err == AGL_BAD_MATCH || err == AGL_BAD_CONTEXT) {
238 if (shareContext && shareContext->d_func()->cx) {
239 qWarning("QGLContext::chooseContext(): Context sharing mismatch!");
240 if (!(ctx = aglCreateContext(fmt, 0)))
241 return false;
242 shareContext = 0;
243 }
244 }
245#else
246 if (shareContext) {
247 ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
248 if (ctx) {
249 qWarning("QGLContext::chooseContext: Context sharing mismatch");
250 shareContext = 0;
251 }
252 }
253#endif
254 if (!ctx) {
255 qWarning("QGLContext::chooseContext: Unable to create QGLContext");
256 return false;
257 }
258 }
259 d->cx = ctx;
260 if (shareContext && shareContext->d_func()->cx) {
261 QGLContext *share = const_cast<QGLContext *>(shareContext);
262 d->sharing = true;
263 share->d_func()->sharing = true;
264 }
265 if (deviceIsPixmap())
266 updatePaintDevice();
267
268 // vblank syncing
269 GLint interval = d->reqFormat.swapInterval();
270 if (interval != -1) {
271#ifndef QT_MAC_USE_COCOA
272 aglSetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
273 if (interval != 0)
274 aglEnable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
275 else
276 aglDisable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
277#else
278 [ctx setValues:&interval forParameter:NSOpenGLCPSwapInterval];
279#endif
280 }
281#ifndef QT_MAC_USE_COCOA
282 aglGetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
283#else
284 [ctx getValues:&interval forParameter:NSOpenGLCPSwapInterval];
285#endif
286 d->glFormat.setSwapInterval(interval);
287 return true;
288}
289
290void *QGLContextPrivate::tryFormat(const QGLFormat &format)
291{
292 static const int Max = 40;
293#ifndef QT_MAC_USE_COCOA
294 GLint attribs[Max], cnt = 0;
295 bool device_is_pixmap = (paintDevice->devType() == QInternal::Pixmap);
296
297 attribs[cnt++] = AGL_RGBA;
298 attribs[cnt++] = AGL_BUFFER_SIZE;
299 attribs[cnt++] = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
300 attribs[cnt++] = AGL_LEVEL;
301 attribs[cnt++] = format.plane();
302
303 if (format.redBufferSize() != -1) {
304 attribs[cnt++] = AGL_RED_SIZE;
305 attribs[cnt++] = format.redBufferSize();
306 }
307 if (format.greenBufferSize() != -1) {
308 attribs[cnt++] = AGL_GREEN_SIZE;
309 attribs[cnt++] = format.greenBufferSize();
310 }
311 if (format.blueBufferSize() != -1) {
312 attribs[cnt++] = AGL_BLUE_SIZE;
313 attribs[cnt++] = format.blueBufferSize();
314 }
315 if (device_is_pixmap) {
316 attribs[cnt++] = AGL_PIXEL_SIZE;
317 attribs[cnt++] = static_cast<QPixmap *>(paintDevice)->depth();
318 attribs[cnt++] = AGL_OFFSCREEN;
319 if (!format.alpha()) {
320 attribs[cnt++] = AGL_ALPHA_SIZE;
321 attribs[cnt++] = 8;
322 }
323 } else {
324 if (format.doubleBuffer())
325 attribs[cnt++] = AGL_DOUBLEBUFFER;
326 }
327
328 if (format.stereo())
329 attribs[cnt++] = AGL_STEREO;
330 if (format.alpha()) {
331 attribs[cnt++] = AGL_ALPHA_SIZE;
332 attribs[cnt++] = format.alphaBufferSize() == -1 ? 8 : format.alphaBufferSize();
333 }
334 if (format.stencil()) {
335 attribs[cnt++] = AGL_STENCIL_SIZE;
336 attribs[cnt++] = format.stencilBufferSize() == -1 ? 8 : format.stencilBufferSize();
337 }
338 if (format.depth()) {
339 attribs[cnt++] = AGL_DEPTH_SIZE;
340 attribs[cnt++] = format.depthBufferSize() == -1 ? 32 : format.depthBufferSize();
341 }
342 if (format.accum()) {
343 attribs[cnt++] = AGL_ACCUM_RED_SIZE;
344 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
345 attribs[cnt++] = AGL_ACCUM_BLUE_SIZE;
346 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
347 attribs[cnt++] = AGL_ACCUM_GREEN_SIZE;
348 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
349 attribs[cnt++] = AGL_ACCUM_ALPHA_SIZE;
350 attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
351 }
352 if (format.sampleBuffers()) {
353 attribs[cnt++] = AGL_SAMPLE_BUFFERS_ARB;
354 attribs[cnt++] = 1;
355 attribs[cnt++] = AGL_SAMPLES_ARB;
356 attribs[cnt++] = format.samples() == -1 ? 4 : format.samples();
357 }
358
359 attribs[cnt] = AGL_NONE;
360 Q_ASSERT(cnt < Max);
361 return aglChoosePixelFormat(0, 0, attribs);
362#else
363 NSOpenGLPixelFormatAttribute attribs[Max];
364 int cnt = 0;
365 int devType = paintDevice->devType();
366 bool device_is_pixmap = (devType == QInternal::Pixmap);
367 int depth = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
368
369 attribs[cnt++] = NSOpenGLPFAColorSize;
370 attribs[cnt++] = depth;
371
372 if (device_is_pixmap) {
373 attribs[cnt++] = NSOpenGLPFAOffScreen;
374 } else {
375 if (format.doubleBuffer())
376 attribs[cnt++] = NSOpenGLPFADoubleBuffer;
377 }
378 if (glFormat.stereo())
379 attribs[cnt++] = NSOpenGLPFAStereo;
380 if (device_is_pixmap || format.alpha()) {
381 attribs[cnt++] = NSOpenGLPFAAlphaSize;
382 attribs[cnt++] = def(format.alphaBufferSize(), 8);
383 }
384 if (format.stencil()) {
385 attribs[cnt++] = NSOpenGLPFAStencilSize;
386 attribs[cnt++] = def(format.stencilBufferSize(), 8);
387 }
388 if (format.depth()) {
389 attribs[cnt++] = NSOpenGLPFADepthSize;
390 attribs[cnt++] = def(format.depthBufferSize(), 32);
391 }
392 if (format.accum()) {
393 attribs[cnt++] = NSOpenGLPFAAccumSize;
394 attribs[cnt++] = def(format.accumBufferSize(), 1);
395 }
396 if (format.sampleBuffers()) {
397 attribs[cnt++] = NSOpenGLPFASampleBuffers;
398 attribs[cnt++] = 1;
399 attribs[cnt++] = NSOpenGLPFASamples;
400 attribs[cnt++] = def(format.samples(), 4);
401 }
402
403 if (format.directRendering())
404 attribs[cnt++] = NSOpenGLPFAAccelerated;
405
406 if (devType == QInternal::Pbuffer)
407 attribs[cnt++] = NSOpenGLPFAPixelBuffer;
408
409 attribs[cnt] = 0;
410 Q_ASSERT(cnt < Max);
411 return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
412#endif
413}
414
415void QGLContextPrivate::clearDrawable()
416{
417 [static_cast<NSOpenGLContext *>(cx) clearDrawable];
418}
419
420/*!
421 \bold{Mac OS X only:} This virtual function tries to find a visual that
422 matches the format, reducing the demands if the original request
423 cannot be met.
424
425 The algorithm for reducing the demands of the format is quite
426 simple-minded, so override this method in your subclass if your
427 application has spcific requirements on visual selection.
428
429 The \a handle argument is always zero and is not used
430
431 \sa chooseContext()
432*/
433
434void *QGLContext::chooseMacVisual(GDHandle /* handle */)
435{
436 Q_D(QGLContext);
437
438 void *fmt = d->tryFormat(d->glFormat);
439 if (!fmt && d->glFormat.stereo()) {
440 d->glFormat.setStereo(false);
441 fmt = d->tryFormat(d->glFormat);
442 }
443 if (!fmt && d->glFormat.sampleBuffers()) {
444 d->glFormat.setSampleBuffers(false);
445 fmt = d->tryFormat(d->glFormat);
446 }
447 if (!fmt)
448 qWarning("QGLContext::chooseMacVisual: Unable to choose a pixel format");
449 return fmt;
450}
451
452void QGLContext::reset()
453{
454 Q_D(QGLContext);
455 if (!d->valid)
456 return;
457 d->cleanup();
458 doneCurrent();
459#ifndef QT_MAC_USE_COCOA
460 if (d->cx)
461 aglDestroyContext((AGLContext)d->cx);
462#else
463 [static_cast<NSOpenGLContext *>(d->cx) release];
464#endif
465 d->cx = 0;
466#ifndef QT_MAC_USE_COCOA
467 if (d->vi)
468 aglDestroyPixelFormat((AGLPixelFormat)d->vi);
469#else
470 [static_cast<NSOpenGLPixelFormat *>(d->vi) release];
471#endif
472 d->vi = 0;
473 d->crWin = false;
474 d->sharing = false;
475 d->valid = false;
476 d->transpColor = QColor();
477 d->initDone = false;
478 qgl_share_reg()->removeShare(this);
479}
480
481void QGLContext::makeCurrent()
482{
483 Q_D(QGLContext);
484
485 if (!d->valid) {
486 qWarning("QGLContext::makeCurrent: Cannot make invalid context current");
487 return;
488 }
489#ifndef QT_MAC_USE_COCOA
490 aglSetCurrentContext((AGLContext)d->cx);
491 if (d->update)
492 updatePaintDevice();
493#else
494 [static_cast<NSOpenGLContext *>(d->cx) makeCurrentContext];
495#endif
496 currentCtx = this;
497 if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
498 qgl_context_storage.setLocalData(new QGLThreadContext);
499 if (qgl_context_storage.hasLocalData())
500 qgl_context_storage.localData()->context = this;
501}
502
503#ifndef QT_MAC_USE_COCOA
504/*
505 Returns the effective scale factor for a widget. For this value to be