mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 08:07:30 +09:00
Issue #1751 -- Remove cocoa and uikit gfx and hal support code
This commit is contained in:
parent
214ac352e5
commit
215e93606d
12 changed files with 1 additions and 2493 deletions
|
|
@ -1,36 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef ForceDiscreteGPUHelperCGL_h_
|
|
||||||
#define ForceDiscreteGPUHelperCGL_h_
|
|
||||||
|
|
||||||
#include <OpenGL/OpenGL.h>
|
|
||||||
|
|
||||||
/** This RAII helper guarantees that we're on the discrete GPU during its lifetime.
|
|
||||||
*
|
|
||||||
* As long as any ForceDiscreteGPUHelperCGL object is alive, we're on the discrete GPU.
|
|
||||||
*/
|
|
||||||
class ForceDiscreteGPUHelperCGL
|
|
||||||
{
|
|
||||||
CGLPixelFormatObj mPixelFormatObj;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ForceDiscreteGPUHelperCGL()
|
|
||||||
{
|
|
||||||
// the code in this function is taken from Chromium, src/ui/gfx/gl/gl_context_cgl.cc, r122013
|
|
||||||
// BSD-style license, (c) The Chromium Authors
|
|
||||||
CGLPixelFormatAttribute attribs[1];
|
|
||||||
attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
|
|
||||||
GLint num_pixel_formats = 0;
|
|
||||||
CGLChoosePixelFormat(attribs, &mPixelFormatObj, &num_pixel_formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
~ForceDiscreteGPUHelperCGL()
|
|
||||||
{
|
|
||||||
CGLReleasePixelFormat(mPixelFormatObj);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ForceDiscreteGPUHelperCGL_h_
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef GLCONTEXTCGL_H_
|
|
||||||
#define GLCONTEXTCGL_H_
|
|
||||||
|
|
||||||
#include "GLContext.h"
|
|
||||||
|
|
||||||
#include "OpenGL/OpenGL.h"
|
|
||||||
|
|
||||||
#ifdef __OBJC__
|
|
||||||
#include <AppKit/NSOpenGL.h>
|
|
||||||
#else
|
|
||||||
typedef void NSOpenGLContext;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
class GLContextCGL : public GLContext
|
|
||||||
{
|
|
||||||
friend class GLContextProviderCGL;
|
|
||||||
|
|
||||||
NSOpenGLContext* const mContext;
|
|
||||||
|
|
||||||
public:
|
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, override)
|
|
||||||
GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
|
|
||||||
NSOpenGLContext* context, bool isOffscreen, ContextProfile profile);
|
|
||||||
|
|
||||||
~GLContextCGL();
|
|
||||||
|
|
||||||
virtual GLContextType GetContextType() const override { return GLContextType::CGL; }
|
|
||||||
|
|
||||||
static GLContextCGL* Cast(GLContext* gl) {
|
|
||||||
MOZ_ASSERT(gl->GetContextType() == GLContextType::CGL);
|
|
||||||
return static_cast<GLContextCGL*>(gl);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Init() override;
|
|
||||||
|
|
||||||
NSOpenGLContext* GetNSOpenGLContext() const { return mContext; }
|
|
||||||
CGLContextObj GetCGLContext() const;
|
|
||||||
|
|
||||||
virtual bool MakeCurrentImpl(bool aForce) override;
|
|
||||||
|
|
||||||
virtual bool IsCurrent() override;
|
|
||||||
|
|
||||||
virtual GLenum GetPreferredARGB32Format() const override;
|
|
||||||
|
|
||||||
virtual bool SetupLookupFunction() override;
|
|
||||||
|
|
||||||
virtual bool IsDoubleBuffered() const override;
|
|
||||||
|
|
||||||
virtual bool SupportsRobustness() const override { return false; }
|
|
||||||
|
|
||||||
virtual bool SwapBuffers() override;
|
|
||||||
|
|
||||||
virtual void GetWSIInfo(nsCString* const out) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace gl
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // GLCONTEXTCGL_H_
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef GLCONTEXTEAGL_H_
|
|
||||||
#define GLCONTEXTEAGL_H_
|
|
||||||
|
|
||||||
#include "GLContext.h"
|
|
||||||
|
|
||||||
#include <CoreGraphics/CoreGraphics.h>
|
|
||||||
#include <OpenGLES/EAGL.h>
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
class GLContextEAGL : public GLContext
|
|
||||||
{
|
|
||||||
friend class GLContextProviderEAGL;
|
|
||||||
|
|
||||||
EAGLContext* const mContext;
|
|
||||||
|
|
||||||
public:
|
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEAGL, override)
|
|
||||||
GLContextEAGL(CreateContextFlags flags, const SurfaceCaps& caps, EAGLContext* context,
|
|
||||||
GLContext* sharedContext, bool isOffscreen, ContextProfile profile);
|
|
||||||
|
|
||||||
~GLContextEAGL();
|
|
||||||
|
|
||||||
virtual GLContextType GetContextType() const override {
|
|
||||||
return GLContextType::EAGL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLContextEAGL* Cast(GLContext* gl) {
|
|
||||||
MOZ_ASSERT(gl->GetContextType() == GLContextType::EAGL);
|
|
||||||
return static_cast<GLContextEAGL*>(gl);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Init() override;
|
|
||||||
|
|
||||||
bool AttachToWindow(nsIWidget* aWidget);
|
|
||||||
|
|
||||||
EAGLContext* GetEAGLContext() const { return mContext; }
|
|
||||||
|
|
||||||
virtual bool MakeCurrentImpl(bool aForce) override;
|
|
||||||
|
|
||||||
virtual bool IsCurrent() override;
|
|
||||||
|
|
||||||
virtual bool SetupLookupFunction() override;
|
|
||||||
|
|
||||||
virtual bool IsDoubleBuffered() const override;
|
|
||||||
|
|
||||||
virtual bool SupportsRobustness() const override { return false; }
|
|
||||||
|
|
||||||
virtual bool SwapBuffers() override;
|
|
||||||
|
|
||||||
virtual void GetWSIInfo(nsCString* const out) const override;
|
|
||||||
|
|
||||||
virtual GLuint GetDefaultFramebuffer() override {
|
|
||||||
return mBackbufferFB;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool RenewSurface(nsIWidget* aWidget) override {
|
|
||||||
// FIXME: should use the passed widget instead of the existing one.
|
|
||||||
return RecreateRB();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
GLuint mBackbufferRB;
|
|
||||||
GLuint mBackbufferFB;
|
|
||||||
|
|
||||||
void* mLayer;
|
|
||||||
|
|
||||||
bool RecreateRB();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace gl
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // GLCONTEXTEAGL_H_
|
|
||||||
|
|
@ -1,397 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "GLContextProvider.h"
|
|
||||||
#include "GLContextCGL.h"
|
|
||||||
#include "nsDebug.h"
|
|
||||||
#include "nsIWidget.h"
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#include "gfxFailure.h"
|
|
||||||
#include "gfxPrefs.h"
|
|
||||||
#include "prenv.h"
|
|
||||||
#include "GeckoProfiler.h"
|
|
||||||
#include "mozilla/gfx/MacIOSurface.h"
|
|
||||||
#include "mozilla/widget/CompositorWidget.h"
|
|
||||||
|
|
||||||
#include <OpenGL/OpenGL.h>
|
|
||||||
|
|
||||||
// When running inside a VM, creating an accelerated OpenGL context usually
|
|
||||||
// fails. Uncomment this line to emulate that behavior.
|
|
||||||
// #define EMULATE_VM
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
using namespace mozilla::gfx;
|
|
||||||
using namespace mozilla::widget;
|
|
||||||
|
|
||||||
class CGLLibrary
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CGLLibrary()
|
|
||||||
: mInitialized(false)
|
|
||||||
, mUseDoubleBufferedWindows(true)
|
|
||||||
, mOGLLibrary(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool EnsureInitialized()
|
|
||||||
{
|
|
||||||
if (mInitialized) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!mOGLLibrary) {
|
|
||||||
mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
|
|
||||||
if (!mOGLLibrary) {
|
|
||||||
NS_WARNING("Couldn't load OpenGL Framework.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* db = PR_GetEnv("MOZ_CGL_DB");
|
|
||||||
if (db) {
|
|
||||||
mUseDoubleBufferedWindows = *db != '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
mInitialized = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UseDoubleBufferedWindows() const {
|
|
||||||
MOZ_ASSERT(mInitialized);
|
|
||||||
return mUseDoubleBufferedWindows;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool mInitialized;
|
|
||||||
bool mUseDoubleBufferedWindows;
|
|
||||||
PRLibrary* mOGLLibrary;
|
|
||||||
};
|
|
||||||
|
|
||||||
CGLLibrary sCGLLibrary;
|
|
||||||
|
|
||||||
GLContextCGL::GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
|
|
||||||
NSOpenGLContext* context, bool isOffscreen,
|
|
||||||
ContextProfile profile)
|
|
||||||
: GLContext(flags, caps, nullptr, isOffscreen)
|
|
||||||
, mContext(context)
|
|
||||||
{
|
|
||||||
SetProfileVersion(profile, 210);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLContextCGL::~GLContextCGL()
|
|
||||||
{
|
|
||||||
MarkDestroyed();
|
|
||||||
[mContext release];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextCGL::Init()
|
|
||||||
{
|
|
||||||
return InitWithPrefix("gl", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
CGLContextObj
|
|
||||||
GLContextCGL::GetCGLContext() const
|
|
||||||
{
|
|
||||||
return static_cast<CGLContextObj>([mContext CGLContextObj]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextCGL::MakeCurrentImpl(bool aForce)
|
|
||||||
{
|
|
||||||
if (IsDestroyed()) {
|
|
||||||
[NSOpenGLContext clearCurrentContext];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aForce && [NSOpenGLContext currentContext] == mContext) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mContext) {
|
|
||||||
[mContext makeCurrentContext];
|
|
||||||
MOZ_ASSERT(IsCurrent());
|
|
||||||
// Use non-blocking swap in "ASAP mode".
|
|
||||||
// ASAP mode means that rendering is iterated as fast as possible.
|
|
||||||
// ASAP mode is entered when layout.frame_rate=0 (requires restart).
|
|
||||||
// If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
|
|
||||||
// When we're iterating as fast as possible, however, we want a non-blocking
|
|
||||||
// glSwapBuffers, which will happen when swapInt==0.
|
|
||||||
GLint swapInt = gfxPrefs::LayoutFrameRate() == 0 ? 0 : 1;
|
|
||||||
[mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextCGL::IsCurrent() {
|
|
||||||
return [NSOpenGLContext currentContext] == mContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum
|
|
||||||
GLContextCGL::GetPreferredARGB32Format() const
|
|
||||||
{
|
|
||||||
return LOCAL_GL_BGRA;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextCGL::SetupLookupFunction()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextCGL::IsDoubleBuffered() const
|
|
||||||
{
|
|
||||||
return sCGLLibrary.UseDoubleBufferedWindows();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextCGL::SwapBuffers()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("GLContextCGL", "SwapBuffers",
|
|
||||||
js::ProfileEntry::Category::GRAPHICS);
|
|
||||||
|
|
||||||
[mContext flushBuffer];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GLContextCGL::GetWSIInfo(nsCString* const out) const
|
|
||||||
{
|
|
||||||
out->AppendLiteral("CGL");
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderCGL::CreateWrappingExisting(void*, void*)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = {
|
|
||||||
NSOpenGLPFAAllowOfflineRenderers,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered_accel[] = {
|
|
||||||
NSOpenGLPFAAccelerated,
|
|
||||||
NSOpenGLPFAAllowOfflineRenderers,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
|
|
||||||
NSOpenGLPFAAllowOfflineRenderers,
|
|
||||||
NSOpenGLPFADoubleBuffer,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel[] = {
|
|
||||||
NSOpenGLPFAAccelerated,
|
|
||||||
NSOpenGLPFAAllowOfflineRenderers,
|
|
||||||
NSOpenGLPFADoubleBuffer,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_allow_offline[] = {
|
|
||||||
NSOpenGLPFAAllowOfflineRenderers,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_accel[] = {
|
|
||||||
NSOpenGLPFAAccelerated,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = {
|
|
||||||
NSOpenGLPFAAccelerated,
|
|
||||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static NSOpenGLContext*
|
|
||||||
CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs)
|
|
||||||
{
|
|
||||||
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
|
|
||||||
initWithAttributes:attribs];
|
|
||||||
if (!format) {
|
|
||||||
NS_WARNING("Failed to create NSOpenGLPixelFormat.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
|
|
||||||
shareContext:nullptr];
|
|
||||||
|
|
||||||
[format release];
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderCGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
|
|
||||||
{
|
|
||||||
return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderCGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
|
|
||||||
{
|
|
||||||
if (!sCGLLibrary.EnsureInitialized()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef EMULATE_VM
|
|
||||||
if (aForceAccelerated) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const NSOpenGLPixelFormatAttribute* attribs;
|
|
||||||
if (sCGLLibrary.UseDoubleBufferedWindows()) {
|
|
||||||
attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
|
|
||||||
} else {
|
|
||||||
attribs = aForceAccelerated ? kAttribs_singleBuffered_accel : kAttribs_singleBuffered;
|
|
||||||
}
|
|
||||||
NSOpenGLContext* context = CreateWithFormat(attribs);
|
|
||||||
if (!context) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make the context transparent
|
|
||||||
GLint opaque = 0;
|
|
||||||
[context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
|
|
||||||
|
|
||||||
SurfaceCaps caps = SurfaceCaps::ForRGBA();
|
|
||||||
ContextProfile profile = ContextProfile::OpenGLCompatibility;
|
|
||||||
RefPtr<GLContextCGL> glContext = new GLContextCGL(CreateContextFlags::NONE, caps,
|
|
||||||
context, false, profile);
|
|
||||||
|
|
||||||
if (!glContext->Init()) {
|
|
||||||
glContext = nullptr;
|
|
||||||
[context release];
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return glContext.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
static already_AddRefed<GLContextCGL>
|
|
||||||
CreateOffscreenFBOContext(CreateContextFlags flags)
|
|
||||||
{
|
|
||||||
if (!sCGLLibrary.EnsureInitialized()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextProfile profile;
|
|
||||||
NSOpenGLContext* context = nullptr;
|
|
||||||
|
|
||||||
if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
|
|
||||||
profile = ContextProfile::OpenGLCore;
|
|
||||||
context = CreateWithFormat(kAttribs_offscreen_coreProfile);
|
|
||||||
}
|
|
||||||
if (!context) {
|
|
||||||
profile = ContextProfile::OpenGLCompatibility;
|
|
||||||
|
|
||||||
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER) {
|
|
||||||
if (gfxPrefs::RequireHardwareGL())
|
|
||||||
context = CreateWithFormat(kAttribs_singleBuffered);
|
|
||||||
else
|
|
||||||
context = CreateWithFormat(kAttribs_offscreen_allow_offline);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (gfxPrefs::RequireHardwareGL())
|
|
||||||
context = CreateWithFormat(kAttribs_offscreen_accel);
|
|
||||||
else
|
|
||||||
context = CreateWithFormat(kAttribs_offscreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!context) {
|
|
||||||
NS_WARNING("Failed to create NSOpenGLContext.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceCaps dummyCaps = SurfaceCaps::Any();
|
|
||||||
RefPtr<GLContextCGL> glContext = new GLContextCGL(flags, dummyCaps, context, true,
|
|
||||||
profile);
|
|
||||||
|
|
||||||
if (gfxPrefs::GLMultithreaded()) {
|
|
||||||
CGLEnable(glContext->GetCGLContext(), kCGLCEMPEngine);
|
|
||||||
}
|
|
||||||
return glContext.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderCGL::CreateHeadless(CreateContextFlags flags,
|
|
||||||
nsACString* const out_failureId)
|
|
||||||
{
|
|
||||||
RefPtr<GLContextCGL> gl;
|
|
||||||
gl = CreateOffscreenFBOContext(flags);
|
|
||||||
if (!gl) {
|
|
||||||
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_FBO");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gl->Init()) {
|
|
||||||
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_INIT");
|
|
||||||
NS_WARNING("Failed during Init.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gl.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderCGL::CreateOffscreen(const IntSize& size,
|
|
||||||
const SurfaceCaps& minCaps,
|
|
||||||
CreateContextFlags flags,
|
|
||||||
nsACString* const out_failureId)
|
|
||||||
{
|
|
||||||
RefPtr<GLContext> gl = CreateHeadless(flags, out_failureId);
|
|
||||||
if (!gl) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gl->InitOffscreen(size, minCaps)) {
|
|
||||||
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_INIT");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gl.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
static RefPtr<GLContext> gGlobalContext;
|
|
||||||
|
|
||||||
GLContext*
|
|
||||||
GLContextProviderCGL::GetGlobalContext()
|
|
||||||
{
|
|
||||||
static bool triedToCreateContext = false;
|
|
||||||
if (!triedToCreateContext) {
|
|
||||||
triedToCreateContext = true;
|
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(!gGlobalContext);
|
|
||||||
nsCString discardFailureId;
|
|
||||||
RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE,
|
|
||||||
&discardFailureId);
|
|
||||||
gGlobalContext = temp;
|
|
||||||
|
|
||||||
if (!gGlobalContext) {
|
|
||||||
NS_WARNING("Couldn't init gGlobalContext.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return gGlobalContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GLContextProviderCGL::Shutdown()
|
|
||||||
{
|
|
||||||
gGlobalContext = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace gl */
|
|
||||||
} /* namespace mozilla */
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "GLContextProvider.h"
|
|
||||||
#include "GLContextEAGL.h"
|
|
||||||
#include "nsDebug.h"
|
|
||||||
#include "nsIWidget.h"
|
|
||||||
#include "gfxPrefs.h"
|
|
||||||
#include "gfxFailure.h"
|
|
||||||
#include "prenv.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/widget/CompositorWidget.h"
|
|
||||||
#include "GeckoProfiler.h"
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
using namespace mozilla::widget;
|
|
||||||
|
|
||||||
GLContextEAGL::GLContextEAGL(CreateContextFlags flags, const SurfaceCaps& caps,
|
|
||||||
EAGLContext* context, GLContext* sharedContext,
|
|
||||||
bool isOffscreen, ContextProfile profile)
|
|
||||||
: GLContext(flags, caps, sharedContext, isOffscreen)
|
|
||||||
, mContext(context)
|
|
||||||
, mBackbufferRB(0)
|
|
||||||
, mBackbufferFB(0)
|
|
||||||
, mLayer(nil)
|
|
||||||
{
|
|
||||||
SetProfileVersion(ContextProfile::OpenGLES,
|
|
||||||
[context API] == kEAGLRenderingAPIOpenGLES3 ? 300 : 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLContextEAGL::~GLContextEAGL()
|
|
||||||
{
|
|
||||||
if (MakeCurrent()) {
|
|
||||||
if (mBackbufferFB) {
|
|
||||||
fDeleteFramebuffers(1, &mBackbufferFB);
|
|
||||||
}
|
|
||||||
if (mBackbufferRB) {
|
|
||||||
fDeleteRenderbuffers(1, &mBackbufferRB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mLayer = nil;
|
|
||||||
MarkDestroyed();
|
|
||||||
[mContext release];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::Init()
|
|
||||||
{
|
|
||||||
return InitWithPrefix("gl", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::AttachToWindow(nsIWidget* aWidget)
|
|
||||||
{
|
|
||||||
// This should only be called once
|
|
||||||
MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
|
|
||||||
|
|
||||||
UIView* view =
|
|
||||||
reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
|
|
||||||
|
|
||||||
if (!view) {
|
|
||||||
MOZ_CRASH("no view!");
|
|
||||||
}
|
|
||||||
|
|
||||||
mLayer = [view layer];
|
|
||||||
|
|
||||||
fGenFramebuffers(1, &mBackbufferFB);
|
|
||||||
return RecreateRB();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::RecreateRB()
|
|
||||||
{
|
|
||||||
MakeCurrent();
|
|
||||||
|
|
||||||
CAEAGLLayer* layer = (CAEAGLLayer*)mLayer;
|
|
||||||
|
|
||||||
if (mBackbufferRB) {
|
|
||||||
// It doesn't seem to be enough to just call renderbufferStorage: below,
|
|
||||||
// we apparently have to recreate the RB.
|
|
||||||
fDeleteRenderbuffers(1, &mBackbufferRB);
|
|
||||||
mBackbufferRB = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fGenRenderbuffers(1, &mBackbufferRB);
|
|
||||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mBackbufferRB);
|
|
||||||
|
|
||||||
[mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER
|
|
||||||
fromDrawable:layer];
|
|
||||||
|
|
||||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
|
|
||||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
|
||||||
LOCAL_GL_RENDERBUFFER, mBackbufferRB);
|
|
||||||
|
|
||||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE == fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::MakeCurrentImpl(bool aForce)
|
|
||||||
{
|
|
||||||
if (!aForce && [EAGLContext currentContext] == mContext) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDestroyed()) {
|
|
||||||
[EAGLContext setCurrentContext:nil];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [EAGLContext setCurrentContext:mContext];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::IsCurrent() {
|
|
||||||
return [EAGLContext currentContext] == mContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::SetupLookupFunction()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::IsDoubleBuffered() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
GLContextEAGL::SwapBuffers()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("GLContextEAGL", "SwapBuffers",
|
|
||||||
js::ProfileEntry::Category::GRAPHICS);
|
|
||||||
|
|
||||||
[mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GLContextEAGL::GetWSIInfo(nsCString* const out) const
|
|
||||||
{
|
|
||||||
out->AppendLiteral("EAGL");
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderEAGL::CreateWrappingExisting(void*, void*)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLContextEAGL*
|
|
||||||
GetGlobalContextEAGL()
|
|
||||||
{
|
|
||||||
return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
static already_AddRefed<GLContext>
|
|
||||||
CreateEAGLContext(CreateContextFlags flags, bool aOffscreen, GLContextEAGL* sharedContext)
|
|
||||||
{
|
|
||||||
EAGLRenderingAPI apis[] = { kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2 };
|
|
||||||
|
|
||||||
// Try to create a GLES3 context if we can, otherwise fall back to GLES2
|
|
||||||
EAGLContext* context = nullptr;
|
|
||||||
for (EAGLRenderingAPI api : apis) {
|
|
||||||
if (sharedContext) {
|
|
||||||
context = [[EAGLContext alloc] initWithAPI:api
|
|
||||||
sharegroup:sharedContext->GetEAGLContext().sharegroup];
|
|
||||||
} else {
|
|
||||||
context = [[EAGLContext alloc] initWithAPI:api];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceCaps caps = SurfaceCaps::ForRGBA();
|
|
||||||
ContextProfile profile = ContextProfile::OpenGLES;
|
|
||||||
RefPtr<GLContextEAGL> glContext = new GLContextEAGL(flags, caps, context,
|
|
||||||
sharedContext,
|
|
||||||
aOffscreen,
|
|
||||||
profile);
|
|
||||||
|
|
||||||
if (!glContext->Init()) {
|
|
||||||
glContext = nullptr;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return glContext.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderEAGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
|
|
||||||
{
|
|
||||||
return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
|
|
||||||
{
|
|
||||||
RefPtr<GLContext> glContext = CreateEAGLContext(CreateContextFlags::NONE, false,
|
|
||||||
GetGlobalContextEAGL());
|
|
||||||
if (!glContext) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aWidget)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return glContext.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderEAGL::CreateHeadless(CreateContextFlags flags,
|
|
||||||
nsACString* const out_failureId)
|
|
||||||
{
|
|
||||||
return CreateEAGLContext(flags, true, GetGlobalContextEAGL());
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<GLContext>
|
|
||||||
GLContextProviderEAGL::CreateOffscreen(const mozilla::gfx::IntSize& size,
|
|
||||||
const SurfaceCaps& caps,
|
|
||||||
CreateContextFlags flags,
|
|
||||||
nsACString* const out_failureId)
|
|
||||||
{
|
|
||||||
RefPtr<GLContext> glContext = CreateHeadless(flags, out_failureId);
|
|
||||||
if (!glContext->InitOffscreen(size, caps)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return glContext.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
static RefPtr<GLContext> gGlobalContext;
|
|
||||||
|
|
||||||
GLContext*
|
|
||||||
GLContextProviderEAGL::GetGlobalContext()
|
|
||||||
{
|
|
||||||
static bool triedToCreateContext = false;
|
|
||||||
if (!triedToCreateContext) {
|
|
||||||
triedToCreateContext = true;
|
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized.");
|
|
||||||
RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE);
|
|
||||||
gGlobalContext = temp;
|
|
||||||
|
|
||||||
if (!gGlobalContext) {
|
|
||||||
MOZ_CRASH("Failed to create global context");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return gGlobalContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GLContextProviderEAGL::Shutdown()
|
|
||||||
{
|
|
||||||
gGlobalContext = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace gl */
|
|
||||||
} /* namespace mozilla */
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
||||||
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "SharedSurfaceIO.h"
|
|
||||||
|
|
||||||
#include "GLContextCGL.h"
|
|
||||||
#include "mozilla/DebugOnly.h"
|
|
||||||
#include "mozilla/gfx/MacIOSurface.h"
|
|
||||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
|
||||||
#include "ScopedGLHelpers.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
/*static*/ UniquePtr<SharedSurface_IOSurface>
|
|
||||||
SharedSurface_IOSurface::Create(const RefPtr<MacIOSurface>& ioSurf,
|
|
||||||
GLContext* gl,
|
|
||||||
bool hasAlpha)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(ioSurf);
|
|
||||||
MOZ_ASSERT(gl);
|
|
||||||
|
|
||||||
auto size = gfx::IntSize::Truncate(ioSurf->GetWidth(), ioSurf->GetHeight());
|
|
||||||
|
|
||||||
typedef SharedSurface_IOSurface ptrT;
|
|
||||||
UniquePtr<ptrT> ret( new ptrT(ioSurf, gl, size, hasAlpha) );
|
|
||||||
return Move(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SharedSurface_IOSurface::ProducerReleaseImpl()
|
|
||||||
{
|
|
||||||
mGL->MakeCurrent();
|
|
||||||
mGL->fFlush();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedSurface_IOSurface::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
|
|
||||||
GLint x, GLint y, GLsizei width, GLsizei height,
|
|
||||||
GLint border)
|
|
||||||
{
|
|
||||||
/* Bug 896693 - OpenGL framebuffers that are backed by IOSurface on OSX expose a bug
|
|
||||||
* in glCopyTexImage2D --- internalformats GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA
|
|
||||||
* return the wrong results. To work around, copy framebuffer to a temporary texture
|
|
||||||
* using GL_RGBA (which works), attach as read framebuffer and glCopyTexImage2D
|
|
||||||
* instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// https://www.opengl.org/sdk/docs/man3/xhtml/glCopyTexImage2D.xml says that width or
|
|
||||||
// height set to 0 results in a NULL texture. Lets not do any work and punt to
|
|
||||||
// original glCopyTexImage2D, since the FBO below will fail when trying to attach a
|
|
||||||
// texture of 0 width or height.
|
|
||||||
if (width == 0 || height == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (internalformat) {
|
|
||||||
case LOCAL_GL_ALPHA:
|
|
||||||
case LOCAL_GL_LUMINANCE:
|
|
||||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mGL->IsCurrent());
|
|
||||||
|
|
||||||
ScopedTexture destTex(mGL);
|
|
||||||
{
|
|
||||||
ScopedBindTexture bindTex(mGL, destTex.Texture());
|
|
||||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
|
|
||||||
LOCAL_GL_NEAREST);
|
|
||||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
|
|
||||||
LOCAL_GL_NEAREST);
|
|
||||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
|
|
||||||
LOCAL_GL_CLAMP_TO_EDGE);
|
|
||||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
|
|
||||||
LOCAL_GL_CLAMP_TO_EDGE);
|
|
||||||
mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, x, y, width,
|
|
||||||
height, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedFramebufferForTexture tmpFB(mGL, destTex.Texture(), LOCAL_GL_TEXTURE_2D);
|
|
||||||
ScopedBindFramebuffer bindFB(mGL, tmpFB.FB());
|
|
||||||
mGL->raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
|
||||||
GLenum format, GLenum type, GLvoid* pixels)
|
|
||||||
{
|
|
||||||
// Calling glReadPixels when an IOSurface is bound to the current framebuffer
|
|
||||||
// can cause corruption in following glReadPixel calls (even if they aren't
|
|
||||||
// reading from an IOSurface).
|
|
||||||
// We workaround this by copying to a temporary texture, and doing the readback
|
|
||||||
// from that.
|
|
||||||
MOZ_ASSERT(mGL->IsCurrent());
|
|
||||||
|
|
||||||
ScopedTexture destTex(mGL);
|
|
||||||
{
|
|
||||||
ScopedFramebufferForTexture srcFB(mGL, ProdTexture(), ProdTextureTarget());
|
|
||||||
|
|
||||||
ScopedBindFramebuffer bindFB(mGL, srcFB.FB());
|
|
||||||
ScopedBindTexture bindTex(mGL, destTex.Texture());
|
|
||||||
mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
|
|
||||||
mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB,
|
|
||||||
x, y,
|
|
||||||
width, height, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedFramebufferForTexture destFB(mGL, destTex.Texture());
|
|
||||||
|
|
||||||
ScopedBindFramebuffer bindFB(mGL, destFB.FB());
|
|
||||||
mGL->raw_fReadPixels(0, 0, width, height, format, type, pixels);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
BackTextureWithIOSurf(GLContext* gl, GLuint tex, MacIOSurface* ioSurf)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(gl->IsCurrent());
|
|
||||||
|
|
||||||
ScopedBindTexture texture(gl, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
|
||||||
|
|
||||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
|
||||||
LOCAL_GL_TEXTURE_MIN_FILTER,
|
|
||||||
LOCAL_GL_LINEAR);
|
|
||||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
|
||||||
LOCAL_GL_TEXTURE_MAG_FILTER,
|
|
||||||
LOCAL_GL_LINEAR);
|
|
||||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
|
||||||
LOCAL_GL_TEXTURE_WRAP_S,
|
|
||||||
LOCAL_GL_CLAMP_TO_EDGE);
|
|
||||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
|
||||||
LOCAL_GL_TEXTURE_WRAP_T,
|
|
||||||
LOCAL_GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
CGLContextObj cgl = GLContextCGL::Cast(gl)->GetCGLContext();
|
|
||||||
MOZ_ASSERT(cgl);
|
|
||||||
|
|
||||||
ioSurf->CGLTexImageIOSurface2D(cgl);
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
|
|
||||||
GLContext* gl,
|
|
||||||
const gfx::IntSize& size,
|
|
||||||
bool hasAlpha)
|
|
||||||
: SharedSurface(SharedSurfaceType::IOSurface,
|
|
||||||
AttachmentType::GLTexture,
|
|
||||||
gl,
|
|
||||||
size,
|
|
||||||
hasAlpha,
|
|
||||||
true)
|
|
||||||
, mIOSurf(ioSurf)
|
|
||||||
{
|
|
||||||
gl->MakeCurrent();
|
|
||||||
mProdTex = 0;
|
|
||||||
gl->fGenTextures(1, &mProdTex);
|
|
||||||
BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedSurface_IOSurface::~SharedSurface_IOSurface()
|
|
||||||
{
|
|
||||||
if (!mGL || !mGL->MakeCurrent())
|
|
||||||
return;
|
|
||||||
|
|
||||||
mGL->fDeleteTextures(1, &mProdTex);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
|
|
||||||
{
|
|
||||||
bool isOpaque = !mHasAlpha;
|
|
||||||
*out_descriptor = layers::SurfaceDescriptorMacIOSurface(mIOSurf->GetIOSurfaceID(),
|
|
||||||
mIOSurf->GetContentsScaleFactor(),
|
|
||||||
isOpaque);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedSurface_IOSurface::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(out_surface);
|
|
||||||
mIOSurf->Lock();
|
|
||||||
size_t bytesPerRow = mIOSurf->GetBytesPerRow();
|
|
||||||
size_t ioWidth = mIOSurf->GetDevicePixelWidth();
|
|
||||||
size_t ioHeight = mIOSurf->GetDevicePixelHeight();
|
|
||||||
|
|
||||||
const unsigned char* ioData = (unsigned char*)mIOSurf->GetBaseAddress();
|
|
||||||
gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
|
|
||||||
if (!map.IsMapped()) {
|
|
||||||
mIOSurf->Unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ioHeight; i++) {
|
|
||||||
memcpy(map.GetData() + i * map.GetStride(),
|
|
||||||
ioData + i * bytesPerRow, ioWidth * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
mIOSurf->Unlock();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// SurfaceFactory_IOSurface
|
|
||||||
|
|
||||||
/*static*/ UniquePtr<SurfaceFactory_IOSurface>
|
|
||||||
SurfaceFactory_IOSurface::Create(GLContext* gl, const SurfaceCaps& caps,
|
|
||||||
const RefPtr<layers::LayersIPCChannel>& allocator,
|
|
||||||
const layers::TextureFlags& flags)
|
|
||||||
{
|
|
||||||
auto maxDims = gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(),
|
|
||||||
MacIOSurface::GetMaxHeight());
|
|
||||||
|
|
||||||
typedef SurfaceFactory_IOSurface ptrT;
|
|
||||||
UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, maxDims) );
|
|
||||||
return Move(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<SharedSurface>
|
|
||||||
SurfaceFactory_IOSurface::CreateShared(const gfx::IntSize& size)
|
|
||||||
{
|
|
||||||
if (size.width > mMaxDims.width ||
|
|
||||||
size.height > mMaxDims.height)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasAlpha = mReadCaps.alpha;
|
|
||||||
RefPtr<MacIOSurface> ioSurf;
|
|
||||||
ioSurf = MacIOSurface::CreateIOSurface(size.width, size.height, 1.0,
|
|
||||||
hasAlpha);
|
|
||||||
|
|
||||||
if (!ioSurf) {
|
|
||||||
NS_WARNING("Failed to create MacIOSurface.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SharedSurface_IOSurface::Create(ioSurf, mGL, hasAlpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace gl
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef SHARED_SURFACEIO_H_
|
|
||||||
#define SHARED_SURFACEIO_H_
|
|
||||||
|
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "SharedSurface.h"
|
|
||||||
|
|
||||||
class MacIOSurface;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
class SharedSurface_IOSurface : public SharedSurface
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const RefPtr<MacIOSurface> mIOSurf;
|
|
||||||
GLuint mProdTex;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static UniquePtr<SharedSurface_IOSurface> Create(const RefPtr<MacIOSurface>& ioSurf,
|
|
||||||
GLContext* gl,
|
|
||||||
bool hasAlpha);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
|
|
||||||
GLContext* gl, const gfx::IntSize& size,
|
|
||||||
bool hasAlpha);
|
|
||||||
|
|
||||||
public:
|
|
||||||
~SharedSurface_IOSurface();
|
|
||||||
|
|
||||||
virtual void LockProdImpl() override { }
|
|
||||||
virtual void UnlockProdImpl() override { }
|
|
||||||
|
|
||||||
virtual void ProducerAcquireImpl() override {}
|
|
||||||
virtual void ProducerReleaseImpl() override;
|
|
||||||
|
|
||||||
virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
|
|
||||||
GLint x, GLint y, GLsizei width, GLsizei height,
|
|
||||||
GLint border) override;
|
|
||||||
virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
|
||||||
GLenum format, GLenum type, GLvoid* pixels) override;
|
|
||||||
|
|
||||||
virtual GLuint ProdTexture() override {
|
|
||||||
return mProdTex;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual GLenum ProdTextureTarget() const override {
|
|
||||||
return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SharedSurface_IOSurface* Cast(SharedSurface* surf) {
|
|
||||||
MOZ_ASSERT(surf->mType == SharedSurfaceType::IOSurface);
|
|
||||||
return static_cast<SharedSurface_IOSurface*>(surf);
|
|
||||||
}
|
|
||||||
|
|
||||||
MacIOSurface* GetIOSurface() const {
|
|
||||||
return mIOSurf;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool NeedsIndirectReads() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
|
||||||
|
|
||||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SurfaceFactory_IOSurface : public SurfaceFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Infallible.
|
|
||||||
static UniquePtr<SurfaceFactory_IOSurface> Create(GLContext* gl,
|
|
||||||
const SurfaceCaps& caps,
|
|
||||||
const RefPtr<layers::LayersIPCChannel>& allocator,
|
|
||||||
const layers::TextureFlags& flags);
|
|
||||||
protected:
|
|
||||||
const gfx::IntSize mMaxDims;
|
|
||||||
|
|
||||||
SurfaceFactory_IOSurface(GLContext* gl, const SurfaceCaps& caps,
|
|
||||||
const RefPtr<layers::LayersIPCChannel>& allocator,
|
|
||||||
const layers::TextureFlags& flags,
|
|
||||||
const gfx::IntSize& maxDims)
|
|
||||||
: SurfaceFactory(SharedSurfaceType::IOSurface, gl, caps, allocator, flags)
|
|
||||||
, mMaxDims(maxDims)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace gl
|
|
||||||
|
|
||||||
} /* namespace mozilla */
|
|
||||||
|
|
||||||
#endif /* SHARED_SURFACEIO_H_ */
|
|
||||||
|
|
@ -7,10 +7,6 @@ gl_provider = 'Null'
|
||||||
|
|
||||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||||
gl_provider = 'WGL'
|
gl_provider = 'WGL'
|
||||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|
||||||
gl_provider = 'CGL'
|
|
||||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
|
|
||||||
gl_provider = 'EAGL'
|
|
||||||
elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||||
if CONFIG['MOZ_EGL_XRENDER_COMPOSITE']:
|
if CONFIG['MOZ_EGL_XRENDER_COMPOSITE']:
|
||||||
gl_provider = 'EGL'
|
gl_provider = 'EGL'
|
||||||
|
|
@ -23,7 +19,6 @@ if CONFIG['MOZ_GL_PROVIDER']:
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'DecomposeIntoNoRepeatTriangles.h',
|
'DecomposeIntoNoRepeatTriangles.h',
|
||||||
'EGLUtils.h',
|
'EGLUtils.h',
|
||||||
'ForceDiscreteGPUHelperCGL.h',
|
|
||||||
'GfxTexturesReporter.h',
|
'GfxTexturesReporter.h',
|
||||||
'GLBlitHelper.h',
|
'GLBlitHelper.h',
|
||||||
'GLConsts.h',
|
'GLConsts.h',
|
||||||
|
|
@ -78,32 +73,7 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']:
|
||||||
# Suppress warnings from Skia header files.
|
# Suppress warnings from Skia header files.
|
||||||
SOURCES['SkiaGLGlue.cpp'].flags += ['-Wno-implicit-fallthrough']
|
SOURCES['SkiaGLGlue.cpp'].flags += ['-Wno-implicit-fallthrough']
|
||||||
|
|
||||||
if gl_provider == 'CGL':
|
if gl_provider == 'GLX':
|
||||||
# These files include Mac headers that are unfriendly to unified builds
|
|
||||||
SOURCES += [
|
|
||||||
"GLContextProviderCGL.mm",
|
|
||||||
]
|
|
||||||
EXPORTS += [
|
|
||||||
'GLContextCGL.h',
|
|
||||||
'SharedSurfaceIO.h',
|
|
||||||
]
|
|
||||||
# SharedSurfaceIO.cpp includes MacIOSurface.h which include Mac headers
|
|
||||||
# which define Size and Point types in root namespace with often conflict with
|
|
||||||
# our own types. While I haven't actually hit this issue in the present case,
|
|
||||||
# it's been an issue in gfx/layers so let's not risk it.
|
|
||||||
SOURCES += [
|
|
||||||
'SharedSurfaceIO.cpp',
|
|
||||||
]
|
|
||||||
elif gl_provider == 'EAGL':
|
|
||||||
# These files include ObjC headers that are unfriendly to unified builds
|
|
||||||
SOURCES += [
|
|
||||||
'GLContextProviderEAGL.mm',
|
|
||||||
]
|
|
||||||
EXPORTS += [
|
|
||||||
'GLContextEAGL.h',
|
|
||||||
]
|
|
||||||
|
|
||||||
elif gl_provider == 'GLX':
|
|
||||||
# GLContextProviderGLX.cpp needs to be kept out of UNIFIED_SOURCES
|
# GLContextProviderGLX.cpp needs to be kept out of UNIFIED_SOURCES
|
||||||
# as it includes X11 headers which cause conflicts.
|
# as it includes X11 headers which cause conflicts.
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
|
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
#include "Hal.h"
|
|
||||||
#include "nsITimer.h"
|
|
||||||
#include "smslib.h"
|
|
||||||
#include "nsComponentManagerUtils.h"
|
|
||||||
|
|
||||||
#include <mach/mach.h>
|
|
||||||
#include <cmath>
|
|
||||||
#import <IOKit/IOKitLib.h>
|
|
||||||
|
|
||||||
#define MEAN_GRAVITY 9.80665
|
|
||||||
#define DEFAULT_SENSOR_POLL 100
|
|
||||||
using namespace mozilla::hal;
|
|
||||||
namespace mozilla {
|
|
||||||
namespace hal_impl {
|
|
||||||
static nsITimer* sUpdateTimer = nullptr;
|
|
||||||
static bool sActiveSensors[NUM_SENSOR_TYPE];
|
|
||||||
static io_connect_t sDataPort = IO_OBJECT_NULL;
|
|
||||||
static uint64_t sLastMean = -1;
|
|
||||||
static float
|
|
||||||
LMUvalueToLux(uint64_t aValue)
|
|
||||||
{
|
|
||||||
//Conversion formula from regression. See Bug 793728.
|
|
||||||
// -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x - 0.19
|
|
||||||
long double powerC4 = 1/pow((long double)10,27);
|
|
||||||
long double powerC3 = 1/pow((long double)10,19);
|
|
||||||
long double powerC2 = 1/pow((long double)10,12);
|
|
||||||
long double powerC1 = 1/pow((long double)10,5);
|
|
||||||
|
|
||||||
long double term4 = -3.0 * powerC4 * pow(aValue,4);
|
|
||||||
long double term3 = 2.6 * powerC3 * pow(aValue,3);
|
|
||||||
long double term2 = -3.4 * powerC2 * pow(aValue,2);
|
|
||||||
long double term1 = 3.9 * powerC1 * aValue;
|
|
||||||
|
|
||||||
float lux = ceil(static_cast<float>(term4 + term3 + term2 + term1 - 0.19));
|
|
||||||
return lux > 0 ? lux : 0;
|
|
||||||
}
|
|
||||||
void
|
|
||||||
UpdateHandler(nsITimer *aTimer, void *aClosure)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
|
|
||||||
if (!sActiveSensors[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SensorType sensor = static_cast<SensorType>(i);
|
|
||||||
InfallibleTArray<float> values;
|
|
||||||
if (sensor == SENSOR_ACCELERATION) {
|
|
||||||
sms_acceleration accel;
|
|
||||||
smsGetData(&accel);
|
|
||||||
|
|
||||||
values.AppendElement(accel.x * MEAN_GRAVITY);
|
|
||||||
values.AppendElement(accel.y * MEAN_GRAVITY);
|
|
||||||
values.AppendElement(accel.z * MEAN_GRAVITY);
|
|
||||||
} else if (sensor == SENSOR_LIGHT && sDataPort != IO_OBJECT_NULL) {
|
|
||||||
kern_return_t kr;
|
|
||||||
uint32_t outputs = 2;
|
|
||||||
uint64_t lightLMU[outputs];
|
|
||||||
|
|
||||||
kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs, nil, 0);
|
|
||||||
if (kr == KERN_SUCCESS) {
|
|
||||||
uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
|
|
||||||
if (mean == sLastMean) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sLastMean = mean;
|
|
||||||
values.AppendElement(LMUvalueToLux(mean));
|
|
||||||
} else if (kr == kIOReturnBusy) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hal::SensorData sdata(sensor,
|
|
||||||
PR_Now(),
|
|
||||||
values,
|
|
||||||
hal::SENSOR_ACCURACY_UNKNOWN);
|
|
||||||
hal::NotifySensorChange(sdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
|
||||||
EnableSensorNotifications(SensorType aSensor)
|
|
||||||
{
|
|
||||||
if (aSensor == SENSOR_ACCELERATION) {
|
|
||||||
int result = smsStartup(nil, nil);
|
|
||||||
|
|
||||||
if (result != SMS_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!smsLoadCalibration()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (aSensor == SENSOR_LIGHT) {
|
|
||||||
io_service_t serviceObject;
|
|
||||||
serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault,
|
|
||||||
IOServiceMatching("AppleLMUController"));
|
|
||||||
if (!serviceObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
kern_return_t kr;
|
|
||||||
kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &sDataPort);
|
|
||||||
IOObjectRelease(serviceObject);
|
|
||||||
if (kr != KERN_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
NS_WARNING("EnableSensorNotifications called on an unknown sensor type");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sActiveSensors[aSensor] = true;
|
|
||||||
|
|
||||||
if (!sUpdateTimer) {
|
|
||||||
CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
|
|
||||||
if (sUpdateTimer) {
|
|
||||||
sUpdateTimer->InitWithFuncCallback(UpdateHandler,
|
|
||||||
nullptr,
|
|
||||||
DEFAULT_SENSOR_POLL,
|
|
||||||
nsITimer::TYPE_REPEATING_SLACK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
|
||||||
DisableSensorNotifications(SensorType aSensor)
|
|
||||||
{
|
|
||||||
if (!sActiveSensors[aSensor] || (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sActiveSensors[aSensor] = false;
|
|
||||||
|
|
||||||
if (aSensor == SENSOR_ACCELERATION) {
|
|
||||||
smsShutdown();
|
|
||||||
} else if (aSensor == SENSOR_LIGHT) {
|
|
||||||
IOServiceClose(sDataPort);
|
|
||||||
}
|
|
||||||
// If all sensors are disabled, cancel the update timer.
|
|
||||||
if (sUpdateTimer) {
|
|
||||||
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
|
|
||||||
if (sActiveSensors[i]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sUpdateTimer->Cancel();
|
|
||||||
NS_RELEASE(sUpdateTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace hal_impl
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
@ -1,159 +0,0 @@
|
||||||
/*
|
|
||||||
* smslib.h
|
|
||||||
*
|
|
||||||
* SMSLib Sudden Motion Sensor Access Library
|
|
||||||
* Copyright (c) 2010 Suitable Systems
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Developed by: Daniel Griscom
|
|
||||||
* Suitable Systems
|
|
||||||
* http://www.suitable.com
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal with the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimers.
|
|
||||||
*
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimers in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* - Neither the names of Suitable Systems nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this Software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* For more information about SMSLib, see
|
|
||||||
* <http://www.suitable.com/tools/smslib.html>
|
|
||||||
* or contact
|
|
||||||
* Daniel Griscom
|
|
||||||
* Suitable Systems
|
|
||||||
* 1 Centre Street, Suite 204
|
|
||||||
* Wakefield, MA 01880
|
|
||||||
* (781) 665-0053
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#define SMSLIB_VERSION "1.8"
|
|
||||||
|
|
||||||
#pragma mark Structure definitions
|
|
||||||
|
|
||||||
// Structure for specifying a 3-axis acceleration. 0.0 means "zero gravities",
|
|
||||||
// 1.0 means "one gravity".
|
|
||||||
typedef struct sms_acceleration {
|
|
||||||
float x; // Right-left acceleration (positive is rightwards)
|
|
||||||
float y; // Front-rear acceleration (positive is rearwards)
|
|
||||||
float z; // Up-down acceleration (positive is upwards)
|
|
||||||
} sms_acceleration;
|
|
||||||
|
|
||||||
// Structure for specifying a calibration.
|
|
||||||
typedef struct sms_calibration {
|
|
||||||
float zeros[3]; // Zero points for three axes (X, Y, Z)
|
|
||||||
float onegs[3]; // One gravity values for three axes
|
|
||||||
} sms_calibration;
|
|
||||||
|
|
||||||
#pragma mark Return value definitions
|
|
||||||
|
|
||||||
// These are the return values for accelStartup(), giving the
|
|
||||||
// various stages where the most successful attempt at accessing
|
|
||||||
// the accelerometer failed. The higher the value, the further along the
|
|
||||||
// software progressed before failing. The options are:
|
|
||||||
// - Didn't match model name
|
|
||||||
#define SMS_FAIL_MODEL (-7)
|
|
||||||
// - Failure getting dictionary matching desired services
|
|
||||||
#define SMS_FAIL_DICTIONARY (-6)
|
|
||||||
// - Failure getting list of services
|
|
||||||
#define SMS_FAIL_LIST_SERVICES (-5)
|
|
||||||
// - Failure if list of services is empty. The process generally fails
|
|
||||||
// here if run on a machine without a Sudden Motion Sensor.
|
|
||||||
#define SMS_FAIL_NO_SERVICES (-4)
|
|
||||||
// - Failure if error opening device.
|
|
||||||
#define SMS_FAIL_OPENING (-3)
|
|
||||||
// - Failure if opened, but didn't get a connection
|
|
||||||
#define SMS_FAIL_CONNECTION (-2)
|
|
||||||
// - Failure if couldn't access connction using given function and size. This
|
|
||||||
// is where the process would probably fail with a change in Apple's API.
|
|
||||||
// Driver problems often also cause failures here.
|
|
||||||
#define SMS_FAIL_ACCESS (-1)
|
|
||||||
// - Success!
|
|
||||||
#define SMS_SUCCESS (0)
|
|
||||||
|
|
||||||
#pragma mark Function declarations
|
|
||||||
|
|
||||||
// This starts up the accelerometer code, trying each possible sensor
|
|
||||||
// specification. Note that for logging purposes it
|
|
||||||
// takes an object and a selector; the object's selector is then invoked
|
|
||||||
// with a single NSString as argument giving progress messages. Example
|
|
||||||
// logging method:
|
|
||||||
// - (void)logMessage: (NSString *)theString
|
|
||||||
// which would be used in accelStartup's invocation thusly:
|
|
||||||
// result = accelStartup(self, @selector(logMessage:));
|
|
||||||
// If the object is nil, then no logging is done. Sets calibation from built-in
|
|
||||||
// value table. Returns ACCEL_SUCCESS for success, and other (negative)
|
|
||||||
// values for various failures (returns value indicating result of
|
|
||||||
// most successful trial).
|
|
||||||
int smsStartup(id logObject, SEL logSelector);
|
|
||||||
|
|
||||||
// This starts up the library in debug mode, ignoring the actual hardware.
|
|
||||||
// Returned data is in the form of 1Hz sine waves, with the X, Y and Z
|
|
||||||
// axes 120 degrees out of phase; "calibrated" data has range +/- (1.0/5);
|
|
||||||
// "uncalibrated" data has range +/- (256/5). X and Y axes centered on 0.0,
|
|
||||||
// Z axes centered on 1 (calibrated) or 256 (uncalibrated).
|
|
||||||
// Don't use smsGetBufferLength or smsGetBufferData. Always returns SMS_SUCCESS.
|
|
||||||
int smsDebugStartup(id logObject, SEL logSelector);
|
|
||||||
|
|
||||||
// Returns the current calibration values.
|
|
||||||
void smsGetCalibration(sms_calibration *calibrationRecord);
|
|
||||||
|
|
||||||
// Sets the calibration, but does NOT store it as a preference. If the argument
|
|
||||||
// is nil then the current calibration is set from the built-in value table.
|
|
||||||
void smsSetCalibration(sms_calibration *calibrationRecord);
|
|
||||||
|
|
||||||
// Stores the current calibration values as a stored preference.
|
|
||||||
void smsStoreCalibration(void);
|
|
||||||
|
|
||||||
// Loads the stored preference values into the current calibration.
|
|
||||||
// Returns YES if successful.
|
|
||||||
BOOL smsLoadCalibration(void);
|
|
||||||
|
|
||||||
// Deletes any stored calibration, and then takes the current calibration values
|
|
||||||
// from the built-in value table.
|
|
||||||
void smsDeleteCalibration(void);
|
|
||||||
|
|
||||||
// Fills in the accel record with calibrated acceleration data. Takes
|
|
||||||
// 1-2ms to return a value. Returns 0 if success, error number if failure.
|
|
||||||
int smsGetData(sms_acceleration *accel);
|
|
||||||
|
|
||||||
// Fills in the accel record with uncalibrated acceleration data.
|
|
||||||
// Returns 0 if success, error number if failure.
|
|
||||||
int smsGetUncalibratedData(sms_acceleration *accel);
|
|
||||||
|
|
||||||
// Returns the length of a raw block of data for the current type of sensor.
|
|
||||||
int smsGetBufferLength(void);
|
|
||||||
|
|
||||||
// Takes a pointer to accelGetRawLength() bytes; sets those bytes
|
|
||||||
// to return value from sensor. Make darn sure the buffer length is right!
|
|
||||||
void smsGetBufferData(char *buffer);
|
|
||||||
|
|
||||||
// This returns an NSString describing the current calibration in
|
|
||||||
// human-readable form. Also include a description of the machine.
|
|
||||||
NSString *smsGetCalibrationDescription(void);
|
|
||||||
|
|
||||||
// Shuts down the accelerometer.
|
|
||||||
void smsShutdown(void);
|
|
||||||
|
|
||||||
|
|
@ -1,938 +0,0 @@
|
||||||
/*
|
|
||||||
* smslib.m
|
|
||||||
*
|
|
||||||
* SMSLib Sudden Motion Sensor Access Library
|
|
||||||
* Copyright (c) 2010 Suitable Systems
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Developed by: Daniel Griscom
|
|
||||||
* Suitable Systems
|
|
||||||
* http://www.suitable.com
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal with the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimers.
|
|
||||||
*
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimers in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* - Neither the names of Suitable Systems nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this Software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* For more information about SMSLib, see
|
|
||||||
* <http://www.suitable.com/tools/smslib.html>
|
|
||||||
* or contact
|
|
||||||
* Daniel Griscom
|
|
||||||
* Suitable Systems
|
|
||||||
* 1 Centre Street, Suite 204
|
|
||||||
* Wakefield, MA 01880
|
|
||||||
* (781) 665-0053
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <IOKit/IOKitLib.h>
|
|
||||||
#import <sys/sysctl.h>
|
|
||||||
#import <math.h>
|
|
||||||
#import "smslib.h"
|
|
||||||
|
|
||||||
#pragma mark Internal structures
|
|
||||||
|
|
||||||
// Represents a single axis of a type of sensor.
|
|
||||||
typedef struct axisStruct {
|
|
||||||
int enabled; // Non-zero if axis is valid in this sensor
|
|
||||||
int index; // Location in struct of first byte
|
|
||||||
int size; // Number of bytes
|
|
||||||
float zerog; // Value meaning "zero g"
|
|
||||||
float oneg; // Change in value meaning "increase of one g"
|
|
||||||
// (can be negative if axis sensor reversed)
|
|
||||||
} axisStruct;
|
|
||||||
|
|
||||||
// Represents the configuration of a type of sensor.
|
|
||||||
typedef struct sensorSpec {
|
|
||||||
const char *model; // Prefix of model to be tested
|
|
||||||
const char *name; // Name of device to be read
|
|
||||||
unsigned int function; // Kernel function index
|
|
||||||
int recordSize; // Size of record to be sent/received
|
|
||||||
axisStruct axes[3]; // Description of three axes (X, Y, Z)
|
|
||||||
} sensorSpec;
|
|
||||||
|
|
||||||
// Configuration of all known types of sensors. The configurations are
|
|
||||||
// tried in order until one succeeds in returning data.
|
|
||||||
// All default values are set here, but each axis' zerog and oneg values
|
|
||||||
// may be changed to saved (calibrated) values.
|
|
||||||
//
|
|
||||||
// These values came from SeisMaCalibrate calibration reports. In general I've
|
|
||||||
// found the following:
|
|
||||||
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the signs
|
|
||||||
// are different (and in one case two axes are swapped)
|
|
||||||
// - PowerBooks and iBooks all have sensors centered on 0, and reading
|
|
||||||
// 50-53 steps per gravity (but with differing polarities!)
|
|
||||||
// - PowerBooks and iBooks of the same model all have the same axis polarities
|
|
||||||
// - PowerBook and iBook access methods are model- and OS version-specific
|
|
||||||
//
|
|
||||||
// So, the sequence of tests is:
|
|
||||||
// - Try model-specific access methods. Note that the test is for a match to the
|
|
||||||
// beginning of the model name, e.g. the record with model name "MacBook"
|
|
||||||
// matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
|
|
||||||
// matches any model).
|
|
||||||
// - If no model-specific record's access fails, then try each model-independent
|
|
||||||
// access method in order, stopping when one works.
|
|
||||||
static const sensorSpec sensors[] = {
|
|
||||||
// ****** Model-dependent methods ******
|
|
||||||
// The PowerBook5,6 is one of the G4 models that seems to lose
|
|
||||||
// SMS access until the next reboot.
|
|
||||||
{"PowerBook5,6", "IOI2CMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, -51.5},
|
|
||||||
{1, 2, 1, 0, -51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// The PowerBook5,7 is one of the G4 models that seems to lose
|
|
||||||
// SMS access until the next reboot.
|
|
||||||
{"PowerBook5,7", "IOI2CMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, 51.5},
|
|
||||||
{1, 2, 1, 0, 51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Access seems to be reliable on the PowerBook5,8
|
|
||||||
{"PowerBook5,8", "PMUMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, -51.5},
|
|
||||||
{1, 1, 1, 0, 51.5},
|
|
||||||
{1, 2, 1, 0, -51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Access seems to be reliable on the PowerBook5,9
|
|
||||||
{"PowerBook5,9", "PMUMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, -51.5},
|
|
||||||
{1, 2, 1, 0, -51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// The PowerBook6,7 is one of the G4 models that seems to lose
|
|
||||||
// SMS access until the next reboot.
|
|
||||||
{"PowerBook6,7", "IOI2CMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, 51.5},
|
|
||||||
{1, 2, 1, 0, 51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// The PowerBook6,8 is one of the G4 models that seems to lose
|
|
||||||
// SMS access until the next reboot.
|
|
||||||
{"PowerBook6,8", "IOI2CMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, 51.5},
|
|
||||||
{1, 2, 1, 0, 51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// MacBook Pro Core 2 Duo 17". Note the reversed Y and Z axes.
|
|
||||||
{"MacBookPro2,1", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, 251},
|
|
||||||
{1, 2, 2, 0, -251},
|
|
||||||
{1, 4, 2, 0, -251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// MacBook Pro Core 2 Duo 15" AND 17" with LED backlight, introduced June '07.
|
|
||||||
// NOTE! The 17" machines have the signs of their X and Y axes reversed
|
|
||||||
// from this calibration, but there's no clear way to discriminate between
|
|
||||||
// the two machines.
|
|
||||||
{"MacBookPro3,1", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, -251},
|
|
||||||
{1, 2, 2, 0, 251},
|
|
||||||
{1, 4, 2, 0, -251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// ... specs?
|
|
||||||
{"MacBook5,2", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, -251},
|
|
||||||
{1, 2, 2, 0, 251},
|
|
||||||
{1, 4, 2, 0, -251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// ... specs?
|
|
||||||
{"MacBookPro5,1", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, -251},
|
|
||||||
{1, 2, 2, 0, -251},
|
|
||||||
{1, 4, 2, 0, 251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// ... specs?
|
|
||||||
{"MacBookPro5,2", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, -251},
|
|
||||||
{1, 2, 2, 0, -251},
|
|
||||||
{1, 4, 2, 0, 251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// This is speculative, based on a single user's report. Looks like the X and Y axes
|
|
||||||
// are swapped. This is true for no other known Appple laptop.
|
|
||||||
{"MacBookPro5,3", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 2, 2, 0, -251},
|
|
||||||
{1, 0, 2, 0, -251},
|
|
||||||
{1, 4, 2, 0, -251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// ... specs?
|
|
||||||
{"MacBookPro5,4", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, -251},
|
|
||||||
{1, 2, 2, 0, -251},
|
|
||||||
{1, 4, 2, 0, 251}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// ****** Model-independent methods ******
|
|
||||||
// Seen once with PowerBook6,8 under system 10.3.9; I suspect
|
|
||||||
// other G4-based 10.3.* systems might use this
|
|
||||||
{"", "IOI2CMotionSensor", 24, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, 51.5},
|
|
||||||
{1, 2, 1, 0, 51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// PowerBook5,6 , PowerBook5,7 , PowerBook6,7 , PowerBook6,8
|
|
||||||
// under OS X 10.4.*
|
|
||||||
{"", "IOI2CMotionSensor", 21, 60, {
|
|
||||||
{1, 0, 1, 0, 51.5},
|
|
||||||
{1, 1, 1, 0, 51.5},
|
|
||||||
{1, 2, 1, 0, 51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// PowerBook5,8 , PowerBook5,9 under OS X 10.4.*
|
|
||||||
{"", "PMUMotionSensor", 21, 60, {
|
|
||||||
// Each has two out of three gains negative, but it's different
|
|
||||||
// for the different models. So, this will be right in two out
|
|
||||||
// of three axis for either model.
|
|
||||||
{1, 0, 1, 0, -51.5},
|
|
||||||
{1, 1, 1, -6, -51.5},
|
|
||||||
{1, 2, 1, 0, -51.5}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// All MacBook, MacBookPro models. Hardware (at least on early MacBookPro 15")
|
|
||||||
// is Kionix KXM52-1050 three-axis accelerometer chip. Data is at
|
|
||||||
// http://kionix.com/Product-Index/product-index.htm. Specific MB and MBP models
|
|
||||||
// that use this are:
|
|
||||||
// MacBook1,1
|
|
||||||
// MacBook2,1
|
|
||||||
// MacBook3,1
|
|
||||||
// MacBook4,1
|
|
||||||
// MacBook5,1
|
|
||||||
// MacBook6,1
|
|
||||||
// MacBookAir1,1
|
|
||||||
// MacBookPro1,1
|
|
||||||
// MacBookPro1,2
|
|
||||||
// MacBookPro4,1
|
|
||||||
// MacBookPro5,5
|
|
||||||
{"", "SMCMotionSensor", 5, 40, {
|
|
||||||
{1, 0, 2, 0, 251},
|
|
||||||
{1, 2, 2, 0, 251},
|
|
||||||
{1, 4, 2, 0, 251}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SENSOR_COUNT (sizeof(sensors)/sizeof(sensorSpec))
|
|
||||||
|
|
||||||
#pragma mark Internal prototypes
|
|
||||||
|
|
||||||
static int getData(sms_acceleration *accel, int calibrated, id logObject, SEL logSelector);
|
|
||||||
static float getAxis(int which, int calibrated);
|
|
||||||
static int signExtend(int value, int size);
|
|
||||||
static NSString *getModelName(void);
|
|
||||||
static NSString *getOSVersion(void);
|
|
||||||
static BOOL loadCalibration(void);
|
|
||||||
static void storeCalibration(void);
|
|
||||||
static void defaultCalibration(void);
|
|
||||||
static void deleteCalibration(void);
|
|
||||||
static int prefIntRead(NSString *prefName, BOOL *success);
|
|
||||||
static void prefIntWrite(NSString *prefName, int prefValue);
|
|
||||||
static float prefFloatRead(NSString *prefName, BOOL *success);
|
|
||||||
static void prefFloatWrite(NSString *prefName, float prefValue);
|
|
||||||
static void prefDelete(NSString *prefName);
|
|
||||||
static void prefSynchronize(void);
|
|
||||||
// static long getMicroseconds(void);
|
|
||||||
float fakeData(NSTimeInterval time);
|
|
||||||
|
|
||||||
#pragma mark Static variables
|
|
||||||
|
|
||||||
static int debugging = NO; // True if debugging (synthetic data)
|
|
||||||
static io_connect_t connection; // Connection for reading accel values
|
|
||||||
static int running = NO; // True if we successfully started
|
|
||||||
static unsigned int sensorNum = 0; // The current index into sensors[]
|
|
||||||
static const char *serviceName; // The name of the current service
|
|
||||||
static char *iRecord, *oRecord; // Pointers to read/write records for sensor
|
|
||||||
static int recordSize; // Size of read/write records
|
|
||||||
static unsigned int function; // Which kernel function should be used
|
|
||||||
static float zeros[3]; // X, Y and Z zero calibration values
|
|
||||||
static float onegs[3]; // X, Y and Z one-g calibration values
|
|
||||||
|
|
||||||
#pragma mark Defines
|
|
||||||
|
|
||||||
// Pattern for building axis letter from axis number
|
|
||||||
#define INT_TO_AXIS(a) (a == 0 ? @"X" : a == 1 ? @"Y" : @"Z")
|
|
||||||
// Name of configuration for given axis' zero (axis specified by integer)
|
|
||||||
#define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)]
|
|
||||||
// Name of configuration for given axis' oneg (axis specified by integer)
|
|
||||||
#define ONEG_NAME(a) [NSString stringWithFormat:@"%@-Axis-One-g", INT_TO_AXIS(a)]
|
|
||||||
// Name of "Is calibrated" preference
|
|
||||||
#define CALIBRATED_NAME (@"Calibrated")
|
|
||||||
// Application domain for SeisMac library
|
|
||||||
#define APP_ID ((CFStringRef)@"com.suitable.SeisMacLib")
|
|
||||||
|
|
||||||
// These #defines make the accelStartup code a LOT easier to read.
|
|
||||||
#undef LOG
|
|
||||||
#define LOG(message) \
|
|
||||||
if (logObject) { \
|
|
||||||
[logObject performSelector:logSelector withObject:message]; \
|
|
||||||
}
|
|
||||||
#define LOG_ARG(format, var1) \
|
|
||||||
if (logObject) { \
|
|
||||||
[logObject performSelector:logSelector \
|
|
||||||
withObject:[NSString stringWithFormat:format, var1]]; \
|
|
||||||
}
|
|
||||||
#define LOG_2ARG(format, var1, var2) \
|
|
||||||
if (logObject) { \
|
|
||||||
[logObject performSelector:logSelector \
|
|
||||||
withObject:[NSString stringWithFormat:format, var1, var2]]; \
|
|
||||||
}
|
|
||||||
#define LOG_3ARG(format, var1, var2, var3) \
|
|
||||||
if (logObject) { \
|
|
||||||
[logObject performSelector:logSelector \
|
|
||||||
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Function definitions
|
|
||||||
|
|
||||||
// This starts up the accelerometer code, trying each possible sensor
|
|
||||||
// specification. Note that for logging purposes it
|
|
||||||
// takes an object and a selector; the object's selector is then invoked
|
|
||||||
// with a single NSString as argument giving progress messages. Example
|
|
||||||
// logging method:
|
|
||||||
// - (void)logMessage: (NSString *)theString
|
|
||||||
// which would be used in accelStartup's invocation thusly:
|
|
||||||
// result = accelStartup(self, @selector(logMessage:));
|
|
||||||
// If the object is nil, then no logging is done. Sets calibation from built-in
|
|
||||||
// value table. Returns ACCEL_SUCCESS for success, and other (negative)
|
|
||||||
// values for various failures (returns value indicating result of
|
|
||||||
// most successful trial).
|
|
||||||
int smsStartup(id logObject, SEL logSelector) {
|
|
||||||
io_iterator_t iterator;
|
|
||||||
io_object_t device;
|
|
||||||
kern_return_t result;
|
|
||||||
sms_acceleration accel;
|
|
||||||
int failure_result = SMS_FAIL_MODEL;
|
|
||||||
|
|
||||||
running = NO;
|
|
||||||
debugging = NO;
|
|
||||||
|
|
||||||
NSString *modelName = getModelName();
|
|
||||||
|
|
||||||
LOG_ARG(@"Machine model: %@\n", modelName);
|
|
||||||
LOG_ARG(@"OS X version: %@\n", getOSVersion());
|
|
||||||
LOG_ARG(@"Accelerometer library version: %s\n", SMSLIB_VERSION);
|
|
||||||
|
|
||||||
for (sensorNum = 0; sensorNum < SENSOR_COUNT; sensorNum++) {
|
|
||||||
|
|
||||||
// Set up all specs for this type of sensor
|
|
||||||
serviceName = sensors[sensorNum].name;
|
|
||||||
recordSize = sensors[sensorNum].recordSize;
|
|
||||||
function = sensors[sensorNum].function;
|
|
||||||
|
|
||||||
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n",
|
|
||||||
serviceName, function, recordSize);
|
|
||||||
|
|
||||||
NSString *targetName = [NSString stringWithCString:sensors[sensorNum].model
|
|
||||||
encoding:NSMacOSRomanStringEncoding];
|
|
||||||
LOG_ARG(@" Comparing model name to target \"%@\": ", targetName);
|
|
||||||
if ([targetName length] == 0 || [modelName hasPrefix:targetName]) {
|
|
||||||
LOG(@"success.\n");
|
|
||||||
} else {
|
|
||||||
LOG(@"failure.\n");
|
|
||||||
// Don't need to increment failure_result.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(@" Fetching dictionary for service: ");
|
|
||||||
CFMutableDictionaryRef dict = IOServiceMatching(serviceName);
|
|
||||||
|
|
||||||
if (dict) {
|
|
||||||
LOG(@"success.\n");
|
|
||||||
} else {
|
|
||||||
LOG(@"failure.\n");
|
|
||||||
if (failure_result < SMS_FAIL_DICTIONARY) {
|
|
||||||
failure_result = SMS_FAIL_DICTIONARY;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(@" Getting list of matching services: ");
|
|
||||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault,
|
|
||||||
dict,
|
|
||||||
&iterator);
|
|
||||||
|
|
||||||
if (result == KERN_SUCCESS) {
|
|
||||||
LOG(@"success.\n");
|
|
||||||
} else {
|
|
||||||
LOG_ARG(@"failure, with return value 0x%x.\n", result);
|
|
||||||
if (failure_result < SMS_FAIL_LIST_SERVICES) {
|
|
||||||
failure_result = SMS_FAIL_LIST_SERVICES;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(@" Getting first device in list: ");
|
|
||||||
device = IOIteratorNext(iterator);
|
|
||||||
|
|
||||||
if (device == 0) {
|
|
||||||
LOG(@"failure.\n");
|
|
||||||
if (failure_result < SMS_FAIL_NO_SERVICES) {
|
|
||||||
failure_result = SMS_FAIL_NO_SERVICES;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
LOG(@"success.\n");
|
|
||||||
LOG(@" Opening device: ");
|
|
||||||
}
|
|
||||||
|
|
||||||
result = IOServiceOpen(device, mach_task_self(), 0, &connection);
|
|
||||||
|
|
||||||
if (result != KERN_SUCCESS) {
|
|
||||||
LOG_ARG(@"failure, with return value 0x%x.\n", result);
|
|
||||||
IOObjectRelease(device);
|
|
||||||
if (failure_result < SMS_FAIL_OPENING) {
|
|
||||||
failure_result = SMS_FAIL_OPENING;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else if (connection == 0) {
|
|
||||||
LOG_ARG(@"'success', but didn't get a connection (return value was: 0x%x).\n", result);
|
|
||||||
IOObjectRelease(device);
|
|
||||||
if (failure_result < SMS_FAIL_CONNECTION) {
|
|
||||||
failure_result = SMS_FAIL_CONNECTION;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
IOObjectRelease(device);
|
|
||||||
LOG(@"success.\n");
|
|
||||||
}
|
|
||||||
LOG(@" Testing device.\n");
|
|
||||||
|
|
||||||
defaultCalibration();
|
|
||||||
|
|
||||||
iRecord = (char*) malloc(recordSize);
|
|
||||||
oRecord = (char*) malloc(recordSize);
|
|
||||||
|
|
||||||
running = YES;
|
|
||||||
result = getData(&accel, true, logObject, logSelector);
|
|
||||||
running = NO;
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
LOG_ARG(@" Failure testing device, with result 0x%x.\n", result);
|
|
||||||
free(iRecord);
|
|
||||||
iRecord = 0;
|
|
||||||
free(oRecord);
|
|
||||||
oRecord = 0;
|
|
||||||
if (failure_result < SMS_FAIL_ACCESS) {
|
|
||||||
failure_result = SMS_FAIL_ACCESS;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
LOG(@" Success testing device!\n");
|
|
||||||
running = YES;
|
|
||||||
return SMS_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return failure_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This starts up the library in debug mode, ignoring the actual hardware.
|
|
||||||
// Returned data is in the form of 1Hz sine waves, with the X, Y and Z
|
|
||||||
// axes 120 degrees out of phase; "calibrated" data has range +/- (1.0/5);
|
|
||||||
// "uncalibrated" data has range +/- (256/5). X and Y axes centered on 0.0,
|
|
||||||
// Z axes centered on 1 (calibrated) or 256 (uncalibrated).
|
|
||||||
// Don't use smsGetBufferLength or smsGetBufferData. Always returns SMS_SUCCESS.
|
|
||||||
int smsDebugStartup(id logObject, SEL logSelector) {
|
|
||||||
LOG(@"Starting up in debug mode\n");
|
|
||||||
debugging = YES;
|
|
||||||
return SMS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the current calibration values.
|
|
||||||
void smsGetCalibration(sms_calibration *calibrationRecord) {
|
|
||||||
int x;
|
|
||||||
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
calibrationRecord->zeros[x] = (debugging ? 0 : zeros[x]);
|
|
||||||
calibrationRecord->onegs[x] = (debugging ? 256 : onegs[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the calibration, but does NOT store it as a preference. If the argument
|
|
||||||
// is nil then the current calibration is set from the built-in value table.
|
|
||||||
void smsSetCalibration(sms_calibration *calibrationRecord) {
|
|
||||||
int x;
|
|
||||||
|
|
||||||
if (!debugging) {
|
|
||||||
if (calibrationRecord) {
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
zeros[x] = calibrationRecord->zeros[x];
|
|
||||||
onegs[x] = calibrationRecord->onegs[x];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
defaultCalibration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stores the current calibration values as a stored preference.
|
|
||||||
void smsStoreCalibration(void) {
|
|
||||||
if (!debugging)
|
|
||||||
storeCalibration();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loads the stored preference values into the current calibration.
|
|
||||||
// Returns YES if successful.
|
|
||||||
BOOL smsLoadCalibration(void) {
|
|
||||||
if (debugging) {
|
|
||||||
return YES;
|
|
||||||
} else if (loadCalibration()) {
|
|
||||||
return YES;
|
|
||||||
} else {
|
|
||||||
defaultCalibration();
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deletes any stored calibration, and then takes the current calibration values
|
|
||||||
// from the built-in value table.
|
|
||||||
void smsDeleteCalibration(void) {
|
|
||||||
if (!debugging) {
|
|
||||||
deleteCalibration();
|
|
||||||
defaultCalibration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fills in the accel record with calibrated acceleration data. Takes
|
|
||||||
// 1-2ms to return a value. Returns 0 if success, error number if failure.
|
|
||||||
int smsGetData(sms_acceleration *accel) {
|
|
||||||
NSTimeInterval time;
|
|
||||||
if (debugging) {
|
|
||||||
usleep(1500); // Usually takes 1-2 milliseconds
|
|
||||||
time = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
accel->x = fakeData(time)/5;
|
|
||||||
accel->y = fakeData(time - 1)/5;
|
|
||||||
accel->z = fakeData(time - 2)/5 + 1.0;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return getData(accel, true, nil, nil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fills in the accel record with uncalibrated acceleration data.
|
|
||||||
// Returns 0 if success, error number if failure.
|
|
||||||
int smsGetUncalibratedData(sms_acceleration *accel) {
|
|
||||||
NSTimeInterval time;
|
|
||||||
if (debugging) {
|
|
||||||
usleep(1500); // Usually takes 1-2 milliseconds
|
|
||||||
time = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
accel->x = fakeData(time) * 256 / 5;
|
|
||||||
accel->y = fakeData(time - 1) * 256 / 5;
|
|
||||||
accel->z = fakeData(time - 2) * 256 / 5 + 256;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return getData(accel, false, nil, nil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the length of a raw block of data for the current type of sensor.
|
|
||||||
int smsGetBufferLength(void) {
|
|
||||||
if (debugging) {
|
|
||||||
return 0;
|
|
||||||
} else if (running) {
|
|
||||||
return sensors[sensorNum].recordSize;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes a pointer to accelGetRawLength() bytes; sets those bytes
|
|
||||||
// to return value from sensor. Make darn sure the buffer length is right!
|
|
||||||
void smsGetBufferData(char *buffer) {
|
|
||||||
IOItemCount iSize = recordSize;
|
|
||||||
IOByteCount oSize = recordSize;
|
|
||||||
kern_return_t result;
|
|
||||||
|
|
||||||
if (debugging || running == NO) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(iRecord, 1, iSize);
|
|
||||||
memset(buffer, 0, oSize);
|
|
||||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
|
||||||
const size_t InStructSize = recordSize;
|
|
||||||
size_t OutStructSize = recordSize;
|
|
||||||
result = IOConnectCallStructMethod(connection,
|
|
||||||
function, // magic kernel function number
|
|
||||||
(const void *)iRecord,
|
|
||||||
InStructSize,
|
|
||||||
(void *)buffer,
|
|
||||||
&OutStructSize
|
|
||||||
);
|
|
||||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
|
||||||
result = IOConnectMethodStructureIStructureO(connection,
|
|
||||||
function, // magic kernel function number
|
|
||||||
iSize,
|
|
||||||
&oSize,
|
|
||||||
iRecord,
|
|
||||||
buffer
|
|
||||||
);
|
|
||||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
|
||||||
|
|
||||||
if (result != KERN_SUCCESS) {
|
|
||||||
running = NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This returns an NSString describing the current calibration in
|
|
||||||
// human-readable form. Also include a description of the machine.
|
|
||||||
NSString *smsGetCalibrationDescription(void) {
|
|
||||||
BOOL success;
|
|
||||||
NSMutableString *s = [[NSMutableString alloc] init];
|
|
||||||
|
|
||||||
if (debugging) {
|
|
||||||
[s release];
|
|
||||||
return @"Debugging!";
|
|
||||||
}
|
|
||||||
|
|
||||||
[s appendString:@"---- SeisMac Calibration Record ----\n \n"];
|
|
||||||
[s appendFormat:@"Machine model: %@\n",
|
|
||||||
getModelName()];
|
|
||||||
[s appendFormat:@"OS X build: %@\n",
|
|
||||||
getOSVersion()];
|
|
||||||
[s appendFormat:@"SeisMacLib version %s, record %d\n \n",
|
|
||||||
SMSLIB_VERSION, sensorNum];
|
|
||||||
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n",
|
|
||||||
serviceName, function, recordSize];
|
|
||||||
if (prefIntRead(CALIBRATED_NAME, &success) && success) {
|
|
||||||
[s appendString:@"Calibration values (from calibration):\n"];
|
|
||||||
} else {
|
|
||||||
[s appendString:@"Calibration values (from defaults):\n"];
|
|
||||||
}
|
|
||||||
[s appendFormat:@" X-Axis-Zero = %.2f\n", zeros[0]];
|
|
||||||
[s appendFormat:@" X-Axis-One-g = %.2f\n", onegs[0]];
|
|
||||||
[s appendFormat:@" Y-Axis-Zero = %.2f\n", zeros[1]];
|
|
||||||
[s appendFormat:@" Y-Axis-One-g = %.2f\n", onegs[1]];
|
|
||||||
[s appendFormat:@" Z-Axis-Zero = %.2f\n", zeros[2]];
|
|
||||||
[s appendFormat:@" Z-Axis-One-g = %.2f\n \n", onegs[2]];
|
|
||||||
[s appendString:@"---- End Record ----\n"];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shuts down the accelerometer.
|
|
||||||
void smsShutdown(void) {
|
|
||||||
if (!debugging) {
|
|
||||||
running = NO;
|
|
||||||
if (iRecord) free(iRecord);
|
|
||||||
if (oRecord) free(oRecord);
|
|
||||||
IOServiceClose(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Internal functions
|
|
||||||
|
|
||||||
// Loads the current calibration from the stored preferences.
|
|
||||||
// Returns true iff successful.
|
|
||||||
BOOL loadCalibration(void) {
|
|
||||||
BOOL thisSuccess, allSuccess;
|
|
||||||
int x;
|
|
||||||
|
|
||||||
prefSynchronize();
|
|
||||||
|
|
||||||
if (prefIntRead(CALIBRATED_NAME, &thisSuccess) && thisSuccess) {
|
|
||||||
// Calibrated. Set all values from saved values.
|
|
||||||
allSuccess = YES;
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
zeros[x] = prefFloatRead(ZERO_NAME(x), &thisSuccess);
|
|
||||||
allSuccess &= thisSuccess;
|
|
||||||
onegs[x] = prefFloatRead(ONEG_NAME(x), &thisSuccess);
|
|
||||||
allSuccess &= thisSuccess;
|
|
||||||
}
|
|
||||||
return allSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stores the current calibration into the stored preferences.
|
|
||||||
static void storeCalibration(void) {
|
|
||||||
int x;
|
|
||||||
prefIntWrite(CALIBRATED_NAME, 1);
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
prefFloatWrite(ZERO_NAME(x), zeros[x]);
|
|
||||||
prefFloatWrite(ONEG_NAME(x), onegs[x]);
|
|
||||||
}
|
|
||||||
prefSynchronize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Sets the calibration to its default values.
|
|
||||||
void defaultCalibration(void) {
|
|
||||||
int x;
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
zeros[x] = sensors[sensorNum].axes[x].zerog;
|
|
||||||
onegs[x] = sensors[sensorNum].axes[x].oneg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deletes the stored preferences.
|
|
||||||
static void deleteCalibration(void) {
|
|
||||||
int x;
|
|
||||||
|
|
||||||
prefDelete(CALIBRATED_NAME);
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
prefDelete(ZERO_NAME(x));
|
|
||||||
prefDelete(ONEG_NAME(x));
|
|
||||||
}
|
|
||||||
prefSynchronize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a named floating point value from the stored preferences. Sets
|
|
||||||
// the success boolean based on, you guessed it, whether it succeeds.
|
|
||||||
static float prefFloatRead(NSString *prefName, BOOL *success) {
|
|
||||||
float result = 0.0f;
|
|
||||||
|
|
||||||
CFPropertyListRef ref = CFPreferencesCopyAppValue((CFStringRef)prefName,
|
|
||||||
APP_ID);
|
|
||||||
// If there isn't such a preference, fail
|
|
||||||
if (ref == NULL) {
|
|
||||||
*success = NO;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
CFTypeID typeID = CFGetTypeID(ref);
|
|
||||||
// Is it a number?
|
|
||||||
if (typeID == CFNumberGetTypeID()) {
|
|
||||||
// Is it a floating point number?
|
|
||||||
if (CFNumberIsFloatType((CFNumberRef)ref)) {
|
|
||||||
// Yup: grab it.
|
|
||||||
*success = CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
|
|
||||||
} else {
|
|
||||||
// Nope: grab as an integer, and convert to a float.
|
|
||||||
long num;
|
|
||||||
if (CFNumberGetValue((CFNumberRef)ref, kCFNumberLongType, &num)) {
|
|
||||||
result = num;
|
|
||||||
*success = YES;
|
|
||||||
} else {
|
|
||||||
*success = NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Or is it a string (e.g. set by the command line "defaults" command)?
|
|
||||||
} else if (typeID == CFStringGetTypeID()) {
|
|
||||||
result = (float)CFStringGetDoubleValue((CFStringRef)ref);
|
|
||||||
*success = YES;
|
|
||||||
} else {
|
|
||||||
// Can't convert to a number: fail.
|
|
||||||
*success = NO;
|
|
||||||
}
|
|
||||||
CFRelease(ref);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a named floating point value to the stored preferences.
|
|
||||||
static void prefFloatWrite(NSString *prefName, float prefValue) {
|
|
||||||
CFNumberRef cfFloat = CFNumberCreate(kCFAllocatorDefault,
|
|
||||||
kCFNumberFloatType,
|
|
||||||
&prefValue);
|
|
||||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
|
||||||
cfFloat,
|
|
||||||
APP_ID);
|
|
||||||
CFRelease(cfFloat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a named integer value from the stored preferences.
|
|
||||||
static int prefIntRead(NSString *prefName, BOOL *success) {
|
|
||||||
Boolean internalSuccess;
|
|
||||||
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName,
|
|
||||||
APP_ID,
|
|
||||||
&internalSuccess);
|
|
||||||
*success = internalSuccess;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a named integer value to the stored preferences.
|
|
||||||
static void prefIntWrite(NSString *prefName, int prefValue) {
|
|
||||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
|
||||||
(CFNumberRef)[NSNumber numberWithInt:prefValue],
|
|
||||||
APP_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deletes the named preference values.
|
|
||||||
static void prefDelete(NSString *prefName) {
|
|
||||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
|
||||||
NULL,
|
|
||||||
APP_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronizes the local preferences with the stored preferences.
|
|
||||||
static void prefSynchronize(void) {
|
|
||||||
CFPreferencesAppSynchronize(APP_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal version of accelGetData, with logging
|
|
||||||
int getData(sms_acceleration *accel, int calibrated, id logObject, SEL logSelector) {
|
|
||||||
IOItemCount iSize = recordSize;
|
|
||||||
IOByteCount oSize = recordSize;
|
|
||||||
kern_return_t result;
|
|
||||||
|
|
||||||
if (running == NO) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(iRecord, 1, iSize);
|
|
||||||
memset(oRecord, 0, oSize);
|
|
||||||
|
|
||||||
LOG_2ARG(@" Querying device (%u, %d): ",
|
|
||||||
sensors[sensorNum].function, sensors[sensorNum].recordSize);
|
|
||||||
|
|
||||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
|
||||||
const size_t InStructSize = recordSize;
|
|
||||||
size_t OutStructSize = recordSize;
|
|
||||||
result = IOConnectCallStructMethod(connection,
|
|
||||||
function, // magic kernel function number
|
|
||||||
(const void *)iRecord,
|
|
||||||
InStructSize,
|
|
||||||
(void *)oRecord,
|
|
||||||
&OutStructSize
|
|
||||||
);
|
|
||||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
|
||||||
result = IOConnectMethodStructureIStructureO(connection,
|
|
||||||
function, // magic kernel function number
|
|
||||||
iSize,
|
|
||||||
&oSize,
|
|
||||||
iRecord,
|
|
||||||
oRecord
|
|
||||||
);
|
|
||||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
|
||||||
|
|
||||||
if (result != KERN_SUCCESS) {
|
|
||||||
LOG(@"failed.\n");
|
|
||||||
running = NO;
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
LOG(@"succeeded.\n");
|
|
||||||
|
|
||||||
accel->x = getAxis(0, calibrated);
|
|
||||||
accel->y = getAxis(1, calibrated);
|
|
||||||
accel->z = getAxis(2, calibrated);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given the returned record, extracts the value of the given axis. If
|
|
||||||
// calibrated, then zero G is 0.0, and one G is 1.0.
|
|
||||||
float getAxis(int which, int calibrated) {
|
|
||||||
// Get various values (to make code cleaner)
|
|
||||||
int indx = sensors[sensorNum].axes[which].index;
|
|
||||||
int size = sensors[sensorNum].axes[which].size;
|
|
||||||
float zerog = zeros[which];
|
|
||||||
float oneg = onegs[which];
|
|
||||||
// Storage for value to be returned
|
|
||||||
int value = 0;
|
|
||||||
|
|
||||||
// Although the values in the returned record should have the proper
|
|
||||||
// endianness, we still have to get it into the proper end of value.
|
|
||||||
#if (BYTE_ORDER == BIG_ENDIAN)
|
|
||||||
// On PowerPC processors
|
|
||||||
memcpy(((char *)&value) + (sizeof(int) - size), &oRecord[indx], size);
|
|
||||||
#endif
|
|
||||||
#if (BYTE_ORDER == LITTLE_ENDIAN)
|
|
||||||
// On Intel processors
|
|
||||||
memcpy(&value, &oRecord[indx], size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
value = signExtend(value, size);
|
|
||||||
|
|
||||||
if (calibrated) {
|
|
||||||
// Scale and shift for zero.
|
|
||||||
return ((float)(value - zerog)) / oneg;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extends the sign, given the length of the value.
|
|
||||||
int signExtend(int value, int size) {
|
|
||||||
// Extend sign
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
if (value & 0x00000080)
|
|
||||||
value |= 0xffffff00;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (value & 0x00008000)
|
|
||||||
value |= 0xffff0000;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (value & 0x00800000)
|
|
||||||
value |= 0xff000000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the model name of the computer (e.g. "MacBookPro1,1")
|
|
||||||
NSString *getModelName(void) {
|
|
||||||
char model[32];
|
|
||||||
size_t len = sizeof(model);
|
|
||||||
int name[2] = {CTL_HW, HW_MODEL};
|
|
||||||
NSString *result;
|
|
||||||
|
|
||||||
if (sysctl(name, 2, &model, &len, NULL, 0) == 0) {
|
|
||||||
result = [NSString stringWithFormat:@"%s", model];
|
|
||||||
} else {
|
|
||||||
result = @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the current OS X version and build (e.g. "10.4.7 (build 8J2135a)")
|
|
||||||
NSString *getOSVersion(void) {
|
|
||||||
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:
|
|
||||||
@"/System/Library/CoreServices/SystemVersion.plist"];
|
|
||||||
NSString *versionString = [dict objectForKey:@"ProductVersion"];
|
|
||||||
NSString *buildString = [dict objectForKey:@"ProductBuildVersion"];
|
|
||||||
NSString *wholeString = [NSString stringWithFormat:@"%@ (build %@)",
|
|
||||||
versionString, buildString];
|
|
||||||
return wholeString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns time within the current second in microseconds.
|
|
||||||
// long getMicroseconds() {
|
|
||||||
// struct timeval t;
|
|
||||||
// gettimeofday(&t, 0);
|
|
||||||
// return t.tv_usec;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Returns fake data given the time. Range is +/-1.
|
|
||||||
float fakeData(NSTimeInterval time) {
|
|
||||||
long secs = lround(floor(time));
|
|
||||||
int secsMod3 = secs % 3;
|
|
||||||
double angle = time * 10 * M_PI * 2;
|
|
||||||
double mag = exp(-(time - (secs - secsMod3)) * 2);
|
|
||||||
return sin(angle) * mag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -40,13 +40,6 @@ elif CONFIG['OS_TARGET'] == 'WINNT':
|
||||||
'fallback/FallbackScreenConfiguration.cpp',
|
'fallback/FallbackScreenConfiguration.cpp',
|
||||||
'windows/WindowsSensor.cpp',
|
'windows/WindowsSensor.cpp',
|
||||||
]
|
]
|
||||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'fallback/FallbackAlarm.cpp',
|
|
||||||
'fallback/FallbackMemory.cpp',
|
|
||||||
'fallback/FallbackPower.cpp',
|
|
||||||
'fallback/FallbackScreenConfiguration.cpp',
|
|
||||||
]
|
|
||||||
elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
|
elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'fallback/FallbackAlarm.cpp',
|
'fallback/FallbackAlarm.cpp',
|
||||||
|
|
@ -79,12 +72,6 @@ UNIFIED_SOURCES += [
|
||||||
'fallback/FallbackNetwork.cpp',
|
'fallback/FallbackNetwork.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'cocoa/CocoaSensor.mm',
|
|
||||||
'cocoa/smslib.mm',
|
|
||||||
]
|
|
||||||
|
|
||||||
IPDL_SOURCES = [
|
IPDL_SOURCES = [
|
||||||
'sandbox/PHal.ipdl',
|
'sandbox/PHal.ipdl',
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue