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
4 : *
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/
9 : *
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
13 : * License.
14 : *
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.
18 : *
19 : * Contributor(s):
20 : * Benoit Jacob <bjacob@mozilla.com>
21 : * Bas Schouten <bschouten@mozilla.com>
22 : * Vladimir Vukicevic <vladimir@pobox.com>
23 : *
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.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "GLContextProvider.h"
39 : #include "GLContext.h"
40 : #include "nsDebug.h"
41 : #include "nsString.h"
42 : #include "nsIWidget.h"
43 : #include "nsDirectoryServiceUtils.h"
44 : #include "nsAppDirectoryServiceDefs.h"
45 : #include "nsIConsoleService.h"
46 : #include "mozilla/Preferences.h"
47 : #include "gfxASurface.h"
48 : #include "gfxImageSurface.h"
49 :
50 : #include "gfxCrashReporterUtils.h"
51 :
52 : // from GL/osmesa.h. We don't include that file so as to avoid having a build-time dependency on OSMesa.
53 : #define OSMESA_RGBA GL_RGBA
54 : #define OSMESA_BGRA 0x1
55 : #define OSMESA_ARGB 0x2
56 : #define OSMESA_RGB GL_RGB
57 : #define OSMESA_BGR 0x4
58 : #define OSMESA_RGB_565 0x5
59 : #define OSMESA_Y_UP 0x11
60 :
61 : namespace mozilla {
62 : namespace gl {
63 :
64 0 : static void LogMessage(const char *msg)
65 : {
66 0 : nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
67 0 : if (console) {
68 0 : console->LogStringMessage(NS_ConvertUTF8toUTF16(nsDependentCString(msg)).get());
69 0 : fprintf(stderr, "%s\n", msg);
70 : }
71 0 : }
72 :
73 : typedef void* PrivateOSMesaContext;
74 :
75 : class OSMesaLibrary
76 : {
77 : public:
78 1464 : OSMesaLibrary() : mInitialized(false), mOSMesaLibrary(nsnull) {}
79 :
80 : typedef PrivateOSMesaContext (GLAPIENTRY * PFNOSMESACREATECONTEXTEXT) (GLenum, GLint, GLint, GLint, PrivateOSMesaContext);
81 : typedef void (GLAPIENTRY * PFNOSMESADESTROYCONTEXT) (PrivateOSMesaContext);
82 : typedef bool (GLAPIENTRY * PFNOSMESAMAKECURRENT) (PrivateOSMesaContext, void *, GLenum, GLsizei, GLsizei);
83 : typedef PrivateOSMesaContext (GLAPIENTRY * PFNOSMESAGETCURRENTCONTEXT) (void);
84 : typedef void (GLAPIENTRY * PFNOSMESAPIXELSTORE) (GLint, GLint);
85 : typedef PRFuncPtr (GLAPIENTRY * PFNOSMESAGETPROCADDRESS) (const char*);
86 :
87 : PFNOSMESACREATECONTEXTEXT fCreateContextExt;
88 : PFNOSMESADESTROYCONTEXT fDestroyContext;
89 : PFNOSMESAMAKECURRENT fMakeCurrent;
90 : PFNOSMESAGETCURRENTCONTEXT fGetCurrentContext;
91 : PFNOSMESAPIXELSTORE fPixelStore;
92 : PFNOSMESAGETPROCADDRESS fGetProcAddress;
93 :
94 : bool EnsureInitialized();
95 :
96 : private:
97 : bool mInitialized;
98 : PRLibrary *mOSMesaLibrary;
99 : };
100 :
101 1464 : OSMesaLibrary sOSMesaLibrary;
102 :
103 : bool
104 0 : OSMesaLibrary::EnsureInitialized()
105 : {
106 0 : if (mInitialized)
107 0 : return true;
108 :
109 0 : nsAdoptingCString osmesalib = Preferences::GetCString("webgl.osmesalib");
110 0 : if (osmesalib.IsEmpty()) {
111 0 : return false;
112 : }
113 :
114 0 : mOSMesaLibrary = PR_LoadLibrary(osmesalib.get());
115 :
116 0 : if (!mOSMesaLibrary) {
117 0 : LogMessage("Couldn't open OSMesa lib for software rendering -- webgl.osmesalib path is incorrect, or not a valid shared library");
118 0 : return false;
119 : }
120 :
121 : LibrarySymbolLoader::SymLoadStruct symbols[] = {
122 : { (PRFuncPtr*) &fCreateContextExt, { "OSMesaCreateContextExt", NULL } },
123 : { (PRFuncPtr*) &fMakeCurrent, { "OSMesaMakeCurrent", NULL } },
124 : { (PRFuncPtr*) &fPixelStore, { "OSMesaPixelStore", NULL } },
125 : { (PRFuncPtr*) &fDestroyContext, { "OSMesaDestroyContext", NULL } },
126 : { (PRFuncPtr*) &fGetCurrentContext, { "OSMesaGetCurrentContext", NULL } },
127 : { (PRFuncPtr*) &fMakeCurrent, { "OSMesaMakeCurrent", NULL } },
128 : { (PRFuncPtr*) &fGetProcAddress, { "OSMesaGetProcAddress", NULL } },
129 : { NULL, { NULL } }
130 0 : };
131 :
132 0 : if (!LibrarySymbolLoader::LoadSymbols(mOSMesaLibrary, &symbols[0])) {
133 0 : LogMessage("Couldn't find required entry points in OSMesa libary");
134 0 : return false;
135 : }
136 :
137 0 : mInitialized = true;
138 0 : return true;
139 : }
140 :
141 : class GLContextOSMesa : public GLContext
142 : {
143 : public:
144 0 : GLContextOSMesa(const ContextFormat& aFormat)
145 : : GLContext(aFormat, true, nsnull),
146 : mThebesSurface(nsnull),
147 0 : mContext(nsnull)
148 : {
149 0 : }
150 :
151 0 : ~GLContextOSMesa()
152 0 : {
153 0 : MarkDestroyed();
154 :
155 0 : if (mContext)
156 0 : sOSMesaLibrary.fDestroyContext(mContext);
157 0 : }
158 :
159 0 : GLContextType GetContextType() {
160 0 : return ContextTypeOSMesa;
161 : }
162 :
163 0 : bool Init(const gfxIntSize &aSize)
164 : {
165 0 : int osmesa_format = -1;
166 0 : int gfxasurface_imageformat = -1;
167 0 : bool format_accepted = false;
168 :
169 0 : if (mCreationFormat.red > 0 &&
170 : mCreationFormat.green > 0 &&
171 : mCreationFormat.blue > 0 &&
172 : mCreationFormat.red <= 8 &&
173 : mCreationFormat.green <= 8 &&
174 : mCreationFormat.blue <= 8)
175 : {
176 0 : if (mCreationFormat.alpha == 0) {
177 : // we can't use OSMESA_BGR because it is packed 24 bits per pixel.
178 : // So we use OSMESA_BGRA and have to use ImageFormatRGB24
179 : // to make sure that the dummy alpha channel is ignored.
180 0 : osmesa_format = OSMESA_BGRA;
181 0 : gfxasurface_imageformat = gfxASurface::ImageFormatRGB24;
182 0 : format_accepted = true;
183 0 : } else if (mCreationFormat.alpha <= 8) {
184 0 : osmesa_format = OSMESA_BGRA;
185 0 : gfxasurface_imageformat = gfxASurface::ImageFormatARGB32;
186 0 : format_accepted = true;
187 : }
188 : }
189 0 : if (!format_accepted) {
190 0 : NS_WARNING("Pixel format not supported with OSMesa.");
191 0 : return false;
192 : }
193 :
194 0 : mThebesSurface = new gfxImageSurface(aSize, gfxASurface::gfxImageFormat(gfxasurface_imageformat));
195 0 : if (mThebesSurface->CairoStatus() != 0) {
196 0 : NS_WARNING("image surface failed");
197 0 : return false;
198 : }
199 :
200 0 : mContext = sOSMesaLibrary.fCreateContextExt(osmesa_format, mCreationFormat.depth, mCreationFormat.stencil, 0, NULL);
201 0 : if (!mContext) {
202 0 : NS_WARNING("OSMesaCreateContextExt failed!");
203 0 : return false;
204 : }
205 :
206 0 : if (!MakeCurrent()) return false;
207 0 : if (!SetupLookupFunction()) return false;
208 :
209 : // OSMesa's different from the other GL providers, it renders to an image surface, not to a pbuffer
210 0 : sOSMesaLibrary.fPixelStore(OSMESA_Y_UP, 0);
211 :
212 0 : return InitWithPrefix("gl", true);
213 : }
214 :
215 0 : bool MakeCurrentImpl(bool aForce = false)
216 : {
217 : bool succeeded
218 0 : = sOSMesaLibrary.fMakeCurrent(mContext, mThebesSurface->Data(),
219 : LOCAL_GL_UNSIGNED_BYTE,
220 : mThebesSurface->Width(),
221 0 : mThebesSurface->Height());
222 0 : NS_ASSERTION(succeeded, "Failed to make OSMesa context current!");
223 :
224 0 : return succeeded;
225 : }
226 :
227 0 : bool SetupLookupFunction()
228 : {
229 0 : mLookupFunc = (PlatformLookupFunction)sOSMesaLibrary.fGetProcAddress;
230 0 : return true;
231 : }
232 :
233 0 : void *GetNativeData(NativeDataType aType)
234 : {
235 0 : switch (aType) {
236 : case NativeImageSurface:
237 0 : return mThebesSurface.get();
238 : default:
239 0 : return nsnull;
240 : }
241 : }
242 :
243 0 : bool SupportsRobustness()
244 : {
245 0 : return false;
246 : }
247 :
248 : private:
249 : nsRefPtr<gfxImageSurface> mThebesSurface;
250 : PrivateOSMesaContext mContext;
251 : };
252 :
253 : already_AddRefed<GLContext>
254 0 : GLContextProviderOSMesa::CreateForWindow(nsIWidget *aWidget)
255 : {
256 0 : return nsnull;
257 : }
258 :
259 : already_AddRefed<GLContext>
260 0 : GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize& aSize,
261 : const ContextFormat& aFormat)
262 : {
263 0 : if (!sOSMesaLibrary.EnsureInitialized()) {
264 0 : return nsnull;
265 : }
266 :
267 0 : ContextFormat actualFormat(aFormat);
268 0 : actualFormat.samples = 0;
269 :
270 0 : nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa(actualFormat);
271 :
272 0 : if (!glContext->Init(aSize))
273 : {
274 0 : return nsnull;
275 : }
276 :
277 0 : return glContext.forget();
278 : }
279 :
280 : GLContext *
281 0 : GLContextProviderOSMesa::GetGlobalContext()
282 : {
283 0 : return nsnull;
284 : }
285 :
286 : void
287 4 : GLContextProviderOSMesa::Shutdown()
288 : {
289 4 : }
290 :
291 : } /* namespace gl */
292 4392 : } /* namespace mozilla */
|