1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Initial Developer of the Original Code is Mozilla Foundation.
16 * Portions created by the Initial Developer are Copyright (C) 2010
17 * the Initial Developer. All Rights Reserved.
20 * Benoit Jacob <bjacob@mozilla.com>
21 * Bas Schouten <bschouten@mozilla.com>
22 * Vladimir Vukicevic <vladimir@pobox.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "GLContextProvider.h"
39 #include "GLContext.h"
42 #include "nsIWidget.h"
43 #include "nsDirectoryServiceUtils.h"
44 #include "nsAppDirectoryServiceDefs.h"
45 #include "nsIConsoleService.h"
46 #include "nsIPrefService.h"
47 #include "gfxASurface.h"
48 #include "gfxImageSurface.h"
50 // from GL/osmesa.h. We don't include that file so as to avoid having a build-time dependency on OSMesa.
51 #define OSMESA_RGBA GL_RGBA
52 #define OSMESA_BGRA 0x1
53 #define OSMESA_ARGB 0x2
54 #define OSMESA_RGB GL_RGB
55 #define OSMESA_BGR 0x4
56 #define OSMESA_RGB_565 0x5
57 #define OSMESA_Y_UP 0x11
62 static void LogMessage(const char *msg
)
64 nsCOMPtr
<nsIConsoleService
> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID
));
66 console
->LogStringMessage(NS_ConvertUTF8toUTF16(nsDependentCString(msg
)).get());
67 fprintf(stderr
, "%s\n", msg
);
71 typedef void* PrivateOSMesaContext
;
76 OSMesaLibrary() : mInitialized(PR_FALSE
), mOSMesaLibrary(nsnull
) {}
78 typedef PrivateOSMesaContext (GLAPIENTRY
* PFNOSMESACREATECONTEXTEXT
) (GLenum
, GLint
, GLint
, GLint
, PrivateOSMesaContext
);
79 typedef void (GLAPIENTRY
* PFNOSMESADESTROYCONTEXT
) (PrivateOSMesaContext
);
80 typedef bool (GLAPIENTRY
* PFNOSMESAMAKECURRENT
) (PrivateOSMesaContext
, void *, GLenum
, GLsizei
, GLsizei
);
81 typedef PrivateOSMesaContext (GLAPIENTRY
* PFNOSMESAGETCURRENTCONTEXT
) (void);
82 typedef void (GLAPIENTRY
* PFNOSMESAPIXELSTORE
) (GLint
, GLint
);
83 typedef PRFuncPtr (GLAPIENTRY
* PFNOSMESAGETPROCADDRESS
) (const char*);
85 PFNOSMESACREATECONTEXTEXT fCreateContextExt
;
86 PFNOSMESADESTROYCONTEXT fDestroyContext
;
87 PFNOSMESAMAKECURRENT fMakeCurrent
;
88 PFNOSMESAGETCURRENTCONTEXT fGetCurrentContext
;
89 PFNOSMESAPIXELSTORE fPixelStore
;
90 PFNOSMESAGETPROCADDRESS fGetProcAddress
;
92 PRBool
EnsureInitialized();
96 PRLibrary
*mOSMesaLibrary
;
99 OSMesaLibrary sOSMesaLibrary
;
102 OSMesaLibrary::EnsureInitialized()
109 nsCOMPtr
<nsIPrefService
> prefService
= do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
);
110 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
112 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
113 rv
= prefService
->GetBranch("webgl.", getter_AddRefs(prefBranch
));
114 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
118 rv
= prefBranch
->GetCharPref("osmesalib", getter_Copies(osmesalib
));
121 osmesalib
.Length() == 0)
126 mOSMesaLibrary
= PR_LoadLibrary(osmesalib
.get());
128 if (!mOSMesaLibrary
) {
129 LogMessage("Couldn't open OSMesa lib for software rendering -- webgl.osmesalib path is incorrect, or not a valid shared library");
133 LibrarySymbolLoader::SymLoadStruct symbols
[] = {
134 { (PRFuncPtr
*) &fCreateContextExt
, { "OSMesaCreateContextExt", NULL
} },
135 { (PRFuncPtr
*) &fMakeCurrent
, { "OSMesaMakeCurrent", NULL
} },
136 { (PRFuncPtr
*) &fPixelStore
, { "OSMesaPixelStore", NULL
} },
137 { (PRFuncPtr
*) &fDestroyContext
, { "OSMesaDestroyContext", NULL
} },
138 { (PRFuncPtr
*) &fGetCurrentContext
, { "OSMesaGetCurrentContext", NULL
} },
139 { (PRFuncPtr
*) &fMakeCurrent
, { "OSMesaMakeCurrent", NULL
} },
140 { (PRFuncPtr
*) &fGetProcAddress
, { "OSMesaGetProcAddress", NULL
} },
144 if (!LibrarySymbolLoader::LoadSymbols(mOSMesaLibrary
, &symbols
[0])) {
145 LogMessage("Couldn't find required entry points in OSMesa libary");
149 mInitialized
= PR_TRUE
;
153 class GLContextOSMesa
: public GLContext
156 GLContextOSMesa(const ContextFormat
& aFormat
)
157 : GLContext(aFormat
, PR_TRUE
, nsnull
),
158 mThebesSurface(nsnull
),
166 sOSMesaLibrary
.fDestroyContext(mContext
);
169 GLContextType
GetContextType() {
170 return ContextTypeOSMesa
;
173 PRBool
Init(const gfxIntSize
&aSize
)
175 int osmesa_format
= -1;
176 int gfxasurface_imageformat
= -1;
177 PRBool format_accepted
= PR_FALSE
;
179 if (mCreationFormat
.red
> 0 &&
180 mCreationFormat
.green
> 0 &&
181 mCreationFormat
.blue
> 0 &&
182 mCreationFormat
.red
<= 8 &&
183 mCreationFormat
.green
<= 8 &&
184 mCreationFormat
.blue
<= 8)
186 if (mCreationFormat
.alpha
== 0) {
187 // we can't use OSMESA_BGR because it is packed 24 bits per pixel.
188 // So we use OSMESA_BGRA and have to use ImageFormatRGB24
189 // to make sure that the dummy alpha channel is ignored.
190 osmesa_format
= OSMESA_BGRA
;
191 gfxasurface_imageformat
= gfxASurface::ImageFormatRGB24
;
192 format_accepted
= PR_TRUE
;
193 } else if (mCreationFormat
.alpha
<= 8) {
194 osmesa_format
= OSMESA_BGRA
;
195 gfxasurface_imageformat
= gfxASurface::ImageFormatARGB32
;
196 format_accepted
= PR_TRUE
;
199 if (!format_accepted
) {
200 NS_WARNING("Pixel format not supported with OSMesa.");
204 mThebesSurface
= new gfxImageSurface(aSize
, gfxASurface::gfxImageFormat(gfxasurface_imageformat
));
205 if (mThebesSurface
->CairoStatus() != 0) {
206 NS_WARNING("image surface failed");
210 mContext
= sOSMesaLibrary
.fCreateContextExt(osmesa_format
, mCreationFormat
.depth
, mCreationFormat
.stencil
, 0, NULL
);
212 NS_WARNING("OSMesaCreateContextExt failed!");
216 if (!MakeCurrent()) return PR_FALSE
;
217 if (!SetupLookupFunction()) return PR_FALSE
;
219 // OSMesa's different from the other GL providers, it renders to an image surface, not to a pbuffer
220 sOSMesaLibrary
.fPixelStore(OSMESA_Y_UP
, 0);
222 return InitWithPrefix("gl", PR_TRUE
);
228 = sOSMesaLibrary
.fMakeCurrent(mContext
, mThebesSurface
->Data(),
229 LOCAL_GL_UNSIGNED_BYTE
,
230 mThebesSurface
->Width(),
231 mThebesSurface
->Height());
232 NS_ASSERTION(succeeded
, "Failed to make OSMesa context current!");
237 PRBool
SetupLookupFunction()
239 mLookupFunc
= (PlatformLookupFunction
)sOSMesaLibrary
.fGetProcAddress
;
243 void *GetNativeData(NativeDataType aType
)
246 case NativeImageSurface
:
247 return mThebesSurface
.get();
254 nsRefPtr
<gfxImageSurface
> mThebesSurface
;
255 PrivateOSMesaContext mContext
;
258 already_AddRefed
<GLContext
>
259 GLContextProviderOSMesa::CreateForWindow(nsIWidget
*aWidget
)
264 already_AddRefed
<GLContext
>
265 GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize
& aSize
,
266 const ContextFormat
& aFormat
)
268 if (!sOSMesaLibrary
.EnsureInitialized()) {
272 nsRefPtr
<GLContextOSMesa
> glContext
= new GLContextOSMesa(aFormat
);
274 if (!glContext
->Init(aSize
))
279 return glContext
.forget();
283 GLContextProviderOSMesa::GetGlobalContext()
289 GLContextProviderOSMesa::Shutdown()
294 } /* namespace mozilla */