OVR: Iterate devices

--HG--
branch : multipass-stereo
This commit is contained in:
kaetemi 2014-08-04 19:19:15 +02:00
parent b9e10fca72
commit f2274d2378
5 changed files with 121 additions and 339 deletions

View file

@ -130,6 +130,7 @@ public:
virtual bool endRenderTarget() = 0; virtual bool endRenderTarget() = 0;
static const char *getLibraryName(CStereoDeviceInfo::TStereoDeviceLibrary library); static const char *getLibraryName(CStereoDeviceInfo::TStereoDeviceLibrary library);
// List all devices. Device creation factories are no longer valid after re-calling this function
static void listDevices(std::vector<CStereoDeviceInfo> &devicesOut); static void listDevices(std::vector<CStereoDeviceInfo> &devicesOut);
static IStereoDisplay *createDevice(const CStereoDeviceInfo &deviceInfo); static IStereoDisplay *createDevice(const CStereoDeviceInfo &deviceInfo);
static void releaseUnusedLibraries(); static void releaseUnusedLibraries();

View file

@ -64,8 +64,7 @@ namespace NL3D {
class ITexture; class ITexture;
class CTextureUser; class CTextureUser;
class CStereoOVRDevicePtr; class CStereoOVRDeviceFactory;
class CStereoOVRDeviceHandle;
/*class CPixelProgramOVR;*/ /*class CPixelProgramOVR;*/
#define NL_STEREO_MAX_USER_CAMERAS 8 #define NL_STEREO_MAX_USER_CAMERAS 8
@ -79,7 +78,7 @@ class CStereoOVRDeviceHandle;
class CStereoOVR : public IStereoHMD class CStereoOVR : public IStereoHMD
{ {
public: public:
CStereoOVR(const CStereoOVRDeviceHandle *handle); CStereoOVR(const CStereoOVRDeviceFactory *handle);
virtual ~CStereoOVR(); virtual ~CStereoOVR();
/// Sets driver and generates necessary render targets /// Sets driver and generates necessary render targets
@ -150,7 +149,7 @@ public:
static void releaseLibrary(); static void releaseLibrary();
private: private:
CStereoOVRDevicePtr *m_DevicePtr; // CStereoOVRDevicePtr *m_DevicePtr;
int m_Stage; int m_Stage;
int m_SubStage; int m_SubStage;
CViewport m_RegularViewport; CViewport m_RegularViewport;

View file

@ -70,87 +70,70 @@ using namespace std;
namespace NL3D { namespace NL3D {
/*extern const char *g_StereoOVR_fp40;
extern const char *g_StereoOVR_arbfp1;
extern const char *g_StereoOVR_ps_2_0;
extern const char *g_StereoOVR_glsl330f;*/
namespace { namespace {
/*
class CStereoOVRLog : public OVR::Log
{
public:
CStereoOVRLog(unsigned logMask = OVR::LogMask_All) : OVR::Log(logMask)
{
} #include "stereo_ovr_04_program.h"
virtual void LogMessageVarg(OVR::LogMessageType messageType, const char* fmt, va_list argList)
{
if (NLMISC::INelContext::isContextInitialised())
{
char buffer[MaxLogBufferMessageSize];
FormatLog(buffer, MaxLogBufferMessageSize, messageType, fmt, argList);
if (IsDebugMessage(messageType))
NLMISC::INelContext::getInstance().getDebugLog()->displayNL("OVR: %s", buffer);
else
NLMISC::INelContext::getInstance().getInfoLog()->displayNL("OVR: %s", buffer);
}
}
};
CStereoOVRLog *s_StereoOVRLog = NULL;
OVR::Ptr<OVR::DeviceManager> s_DeviceManager;
class CStereoOVRSystem class CStereoOVRSystem
{ {
public: public:
~CStereoOVRSystem() CStereoOVRSystem() : m_InitOk(false)
{ {
Release();
} }
void Init() ~CStereoOVRSystem()
{ {
if (!s_StereoOVRLog) if (m_InitOk)
{ {
nldebug("Initialize OVR"); nlwarning("OVR: Not all resources were released before exit");
s_StereoOVRLog = new CStereoOVRLog(); Release();
} }
if (!OVR::System::IsInitialized()) }
OVR::System::Init(s_StereoOVRLog);
if (!s_DeviceManager) bool Init()
s_DeviceManager = OVR::DeviceManager::Create(); {
if (!m_InitOk)
{
nldebug("OVR: Initialize");
m_InitOk = ovr_Initialize();
nlassert(m_InitOk);
}
return m_InitOk;
} }
void Release() void Release()
{ {
if (s_DeviceManager) if (m_InitOk)
{ {
nldebug("Release OVR"); nldebug("OVR: Release");
s_DeviceManager->Release(); ovr_Shutdown();
m_InitOk = false;
} }
s_DeviceManager.Clear();
if (OVR::System::IsInitialized())
OVR::System::Destroy();
if (s_StereoOVRLog)
nldebug("Release OVR Ok");
delete s_StereoOVRLog;
s_StereoOVRLog = NULL;
} }
private:
bool m_InitOk;
}; };
CStereoOVRSystem s_StereoOVRSystem; CStereoOVRSystem s_StereoOVRSystem;
sint s_DeviceCounter = 0; sint s_DeviceCounter = 0;
*/ uint s_DetectId = 0;
} }
/*
class CStereoOVRDeviceHandle : public IStereoDeviceFactory class CStereoOVRDeviceFactory : public IStereoDeviceFactory
{ {
public: public:
// fixme: virtual destructor??? uint DeviceIndex;
OVR::DeviceEnumerator<OVR::HMDDevice> DeviceHandle; uint DetectId;
bool DebugDevice;
ovrHmdType DebugDeviceType;
IStereoDisplay *createDevice() const IStereoDisplay *createDevice() const
{ {
CStereoOVR *stereo = new CStereoOVR(this); CStereoOVR *stereo = new CStereoOVR(this);
@ -161,6 +144,7 @@ public:
} }
}; };
/*
class CStereoOVRDevicePtr class CStereoOVRDevicePtr
{ {
public: public:
@ -170,7 +154,8 @@ public:
OVR::HMDInfo HMDInfo; OVR::HMDInfo HMDInfo;
}; };
*/ */
CStereoOVR::CStereoOVR(const CStereoOVRDeviceHandle *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), /*m_SceneTexture(NULL),*/ m_GUITexture(NULL), /*m_PixelProgram(NULL),*/ m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f)
CStereoOVR::CStereoOVR(const CStereoOVRDeviceFactory *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), /*m_SceneTexture(NULL),*/ m_GUITexture(NULL), /*m_PixelProgram(NULL),*/ m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f)
{ {
/*++s_DeviceCounter; /*++s_DeviceCounter;
m_DevicePtr = new CStereoOVRDevicePtr(); m_DevicePtr = new CStereoOVRDevicePtr();
@ -958,48 +943,84 @@ void CStereoOVR::setScale(float s)
m_Scale = s; m_Scale = s;
} }
void CStereoOVR::listDevices(std::vector<CStereoDeviceInfo> &devicesOut) void CStereoOVR::listDevices(std::vector<CStereoDeviceInfo> &devicesOut)
{ {
/* if (!s_StereoOVRSystem.Init())
s_StereoOVRSystem.Init(); return;
OVR::DeviceEnumerator<OVR::HMDDevice> devices = s_DeviceManager->EnumerateDevices<OVR::HMDDevice>();
uint id = 1; ++s_DetectId;
do uint hmdDetect = ovrHmd_Detect();
nldebug("OVR: Detected %u HMDs", hmdDetect);
for (uint i = 0; i < hmdDetect; ++i)
{ {
CStereoDeviceInfo deviceInfoOut; devicesOut.resize(devicesOut.size() + 1);
OVR::DeviceInfo deviceInfo; CStereoDeviceInfo &deviceInfoOut = devicesOut[devicesOut.size() - 1];
if (devices.IsAvailable()) ovrHmd hmd = ovrHmd_Create(i);
{ CStereoOVRDeviceFactory *factory = new CStereoOVRDeviceFactory();
devices.GetDeviceInfo(&deviceInfo); factory->DetectId = s_DetectId;
CStereoOVRDeviceHandle *handle = new CStereoOVRDeviceHandle(); factory->DeviceIndex = i;
deviceInfoOut.Factory = static_cast<IStereoDeviceFactory *>(handle); factory->DebugDevice = false;
handle->DeviceHandle = devices; deviceInfoOut.Factory = factory;
deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD; // 1; // OVR::HMDDevice deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD;
deviceInfoOut.Library = CStereoDeviceInfo::OVR; // "Oculus SDK"; deviceInfoOut.Library = CStereoDeviceInfo::OVR;
deviceInfoOut.Manufacturer = deviceInfo.Manufacturer; deviceInfoOut.Manufacturer = hmd->Manufacturer;
deviceInfoOut.ProductName = deviceInfo.ProductName; deviceInfoOut.ProductName = hmd->ProductName;
deviceInfoOut.AllowAuto = true; deviceInfoOut.AllowAuto = true;
stringstream ser; deviceInfoOut.Serial = hmd->SerialNumber;
ser << id; ovrHmd_Destroy(hmd);
deviceInfoOut.Serial = ser.str(); // can't get the real serial from the sdk...
devicesOut.push_back(deviceInfoOut);
++id;
} }
} while (devices.Next());*/ #if !FINAL_VERSION
// Debug DK1
{
devicesOut.resize(devicesOut.size() + 1);
CStereoDeviceInfo &deviceInfoOut = devicesOut[devicesOut.size() - 1];
ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK1);
CStereoOVRDeviceFactory *factory = new CStereoOVRDeviceFactory();
factory->DebugDevice = true;
factory->DebugDeviceType = ovrHmd_DK1;
deviceInfoOut.Factory = factory;
deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD;
deviceInfoOut.Library = CStereoDeviceInfo::OVR;
deviceInfoOut.Manufacturer = hmd->Manufacturer;
deviceInfoOut.ProductName = hmd->ProductName;
deviceInfoOut.AllowAuto = false;
deviceInfoOut.Serial = "OVR-DK1-DEBUG";
ovrHmd_Destroy(hmd);
}
// Debug DK2
{
devicesOut.resize(devicesOut.size() + 1);
CStereoDeviceInfo &deviceInfoOut = devicesOut[devicesOut.size() - 1];
ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
CStereoOVRDeviceFactory *factory = new CStereoOVRDeviceFactory();
factory->DebugDevice = true;
factory->DebugDeviceType = ovrHmd_DK2;
deviceInfoOut.Factory = factory;
deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD;
deviceInfoOut.Library = CStereoDeviceInfo::OVR;
deviceInfoOut.Manufacturer = hmd->Manufacturer;
deviceInfoOut.ProductName = hmd->ProductName;
deviceInfoOut.AllowAuto = false;
deviceInfoOut.Serial = "OVR-DK2-DEBUG";
ovrHmd_Destroy(hmd);
}
#endif
} }
bool CStereoOVR::isLibraryInUse() bool CStereoOVR::isLibraryInUse()
{ {
/*nlassert(s_DeviceCounter >= 0); nlassert(s_DeviceCounter >= 0);
return s_DeviceCounter > 0;*/ return s_DeviceCounter > 0;
return false;
} }
void CStereoOVR::releaseLibrary() void CStereoOVR::releaseLibrary()
{ {
/*nlassert(s_DeviceCounter == 0); nlassert(s_DeviceCounter == 0);
s_StereoOVRSystem.Release();*/ s_StereoOVRSystem.Release();
} }
bool CStereoOVR::isDeviceCreated() bool CStereoOVR::isDeviceCreated()

View file

@ -1,249 +1,4 @@
/************************************************************************************
Filename : stereo_ovf_fp.cpp // TODO
Content : Barrel fragment program compiled to a blob of assembly
Created : July 01, 2013
Modified by : Jan Boon (Kaetemi)
Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************************/
namespace NL3D {
const char *g_StereoOVR_fp40 =
"!!ARBfp1.0\n"
"OPTION NV_fragment_program2;\n"
//# cgc version 3.1.0013, build date Apr 18 2012
//# command line args: -profile fp40
//# source file: pp_oculus_vr.cg
//#vendor NVIDIA Corporation
//#version 3.1.0.13
//#profile fp40
//#program pp_oculus_vr
//#semantic pp_oculus_vr.cLensCenter
//#semantic pp_oculus_vr.cScreenCenter
//#semantic pp_oculus_vr.cScale
//#semantic pp_oculus_vr.cScaleIn
//#semantic pp_oculus_vr.cHmdWarpParam
//#semantic pp_oculus_vr.cTex0 : TEX0
//#var float2 texCoord : $vin.TEXCOORD0 : TEX0 : 0 : 1
//#var float2 cLensCenter : : c[0] : 1 : 1
//#var float2 cScreenCenter : : c[1] : 2 : 1
//#var float2 cScale : : c[2] : 3 : 1
//#var float2 cScaleIn : : c[3] : 4 : 1
//#var float4 cHmdWarpParam : : c[4] : 5 : 1
//#var sampler2D nlTex0 : TEX0 : texunit 0 : 6 : 1
//#var float4 oCol : $vout.COLOR : COL : 7 : 1
//#const c[5] = 0.25 0.5 0
"PARAM c[6] = { program.env[0..4],\n" // program.local->program.env!
" { 0.25, 0.5, 0 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"SHORT TEMP H0;\n"
"TEMP RC;\n"
"TEMP HC;\n"
"OUTPUT oCol = result.color;\n"
"ADDR R0.xy, fragment.texcoord[0], -c[0];\n"
"MULR R0.xy, R0, c[3];\n"
"MULR R0.z, R0.y, R0.y;\n"
"MADR R1.x, R0, R0, R0.z;\n"
"MULR R0.zw, R1.x, c[4].xywz;\n"
"MADR R1.y, R1.x, c[4], c[4].x;\n"
"MADR R0.w, R0, R1.x, R1.y;\n"
"MULR R0.z, R0, R1.x;\n"
"MADR R0.z, R0, R1.x, R0.w;\n"
"MULR R1.xy, R0, R0.z;\n"
"MOVR R0.xy, c[5];\n"
"ADDR R1.zw, R0.xyxy, c[1].xyxy;\n"
"MOVR R0.zw, c[0].xyxy;\n"
"MADR R0.zw, R1.xyxy, c[2].xyxy, R0;\n"
"MINR R1.xy, R0.zwzw, R1.zwzw;\n"
"ADDR R0.xy, -R0, c[1];\n"
"MAXR R0.xy, R0, R1;\n"
"SEQR H0.xy, R0, R0.zwzw;\n"
"MULXC HC.x, H0, H0.y;\n"
"IF EQ.x;\n"
"MOVR oCol, c[5].z;\n"
"ELSE;\n"
"TEX oCol, R0.zwzw, texture[0], 2D;\n"
"ENDIF;\n"
"END\n";
//# 24 instructions, 2 R-regs, 1 H-regs
const char *g_StereoOVR_arbfp1 =
"!!ARBfp1.0\n"
//# cgc version 3.1.0013, build date Apr 18 2012
//# command line args: -profile arbfp1
//# source file: pp_oculus_vr.cg
//#vendor NVIDIA Corporation
//#version 3.1.0.13
//#profile arbfp1
//#program pp_oculus_vr
//#semantic pp_oculus_vr.cLensCenter
//#semantic pp_oculus_vr.cScreenCenter
//#semantic pp_oculus_vr.cScale
//#semantic pp_oculus_vr.cScaleIn
//#semantic pp_oculus_vr.cHmdWarpParam
//#semantic pp_oculus_vr.cTex0 : TEX0
//#var float2 texCoord : $vin.TEXCOORD0 : TEX0 : 0 : 1
//#var float2 cLensCenter : : c[0] : 1 : 1
//#var float2 cScreenCenter : : c[1] : 2 : 1
//#var float2 cScale : : c[2] : 3 : 1
//#var float2 cScaleIn : : c[3] : 4 : 1
//#var float4 cHmdWarpParam : : c[4] : 5 : 1
//#var sampler2D nlTex0 : TEX0 : texunit 0 : 6 : 1
//#var float4 oCol : $vout.COLOR : COL : 7 : 1
//#const c[5] = 0.25 0.5 0 1
"PARAM c[6] = { program.env[0..4],\n"
" { 0.25, 0.5, 0, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"ADD R0.xy, fragment.texcoord[0], -c[0];\n"
"MUL R0.xy, R0, c[3];\n"
"MUL R0.z, R0.y, R0.y;\n"
"MAD R0.z, R0.x, R0.x, R0;\n"
"MUL R0.w, R0.z, c[4];\n"
"MUL R0.w, R0, R0.z;\n"
"MAD R1.y, R0.z, c[4], c[4].x;\n"
"MUL R1.x, R0.z, c[4].z;\n"
"MAD R1.x, R0.z, R1, R1.y;\n"
"MAD R0.z, R0.w, R0, R1.x;\n"
"MUL R0.xy, R0, R0.z;\n"
"MOV R0.zw, c[5].xyxy;\n"
"ADD R1.xy, R0.zwzw, c[1];\n"
"MUL R0.xy, R0, c[2];\n"
"ADD R0.xy, R0, c[0];\n"
"MIN R1.xy, R1, R0;\n"
"ADD R0.zw, -R0, c[1].xyxy;\n"
"MAX R0.zw, R0, R1.xyxy;\n"
"ADD R0.zw, R0, -R0.xyxy;\n"
"ABS R0.zw, R0;\n"
"CMP R0.zw, -R0, c[5].z, c[5].w;\n"
"MUL R0.z, R0, R0.w;\n"
"ABS R0.z, R0;\n"
"CMP R0.z, -R0, c[5], c[5].w;\n"
"ABS R1.x, R0.z;\n"
"TEX R0, R0, texture[0], 2D;\n"
"CMP R1.x, -R1, c[5].z, c[5].w;\n"
"CMP result.color, -R1.x, R0, c[5].z;\n"
"END\n";
//# 28 instructions, 2 R-regs
const char *g_StereoOVR_ps_2_0 =
"ps_2_0\n"
// cgc version 3.1.0013, build date Apr 18 2012
// command line args: -profile ps_2_0
// source file: pp_oculus_vr.cg
//vendor NVIDIA Corporation
//version 3.1.0.13
//profile ps_2_0
//program pp_oculus_vr
//semantic pp_oculus_vr.cLensCenter
//semantic pp_oculus_vr.cScreenCenter
//semantic pp_oculus_vr.cScale
//semantic pp_oculus_vr.cScaleIn
//semantic pp_oculus_vr.cHmdWarpParam
//semantic pp_oculus_vr.cTex0 : TEX0
//var float2 texCoord : $vin.TEXCOORD0 : TEX0 : 0 : 1
//var float2 cLensCenter : : c[0] : 1 : 1
//var float2 cScreenCenter : : c[1] : 2 : 1
//var float2 cScale : : c[2] : 3 : 1
//var float2 cScaleIn : : c[3] : 4 : 1
//var float4 cHmdWarpParam : : c[4] : 5 : 1
//var sampler2D nlTex0 : TEX0 : texunit 0 : 6 : 1
//var float4 oCol : $vout.COLOR : COL : 7 : 1
//const c[5] = -0.25 -0.5 0.25 0.5
//const c[6] = 1 0
"dcl_2d s0\n"
"def c5, -0.25000000, -0.50000000, 0.25000000, 0.50000000\n"
"def c6, 1.00000000, 0.00000000, 0, 0\n"
"dcl t0.xy\n"
"add r0.xy, t0, -c0\n"
"mul r4.xy, r0, c3\n"
"mul r0.x, r4.y, r4.y\n"
"mad r0.x, r4, r4, r0\n"
"mul r1.x, r0, c4.w\n"
"mul r1.x, r1, r0\n"
"mad r3.x, r0, c4.y, c4\n"
"mul r2.x, r0, c4.z\n"
"mad r2.x, r0, r2, r3\n"
"mad r0.x, r1, r0, r2\n"
"mul r0.xy, r4, r0.x\n"
"mul r0.xy, r0, c2\n"
"add r3.xy, r0, c0\n"
"mov r1.x, c5.z\n"
"mov r1.y, c5.w\n"
"mov r2.xy, c1\n"
"add r2.xy, r1, r2\n"
"mov r1.xy, c1\n"
"min r2.xy, r2, r3\n"
"add r1.xy, c5, r1\n"
"max r1.xy, r1, r2\n"
"add r1.xy, r1, -r3\n"
"abs r1.xy, r1\n"
"cmp r1.xy, -r1, c6.x, c6.y\n"
"mul_pp r1.x, r1, r1.y\n"
"abs_pp r1.x, r1\n"
"cmp_pp r1.x, -r1, c6, c6.y\n"
"abs_pp r1.x, r1\n"
"texld r0, r3, s0\n"
"cmp r0, -r1.x, r0, c6.y\n"
"mov oC0, r0\n";
const char *g_StereoOVR_glsl330f =
"#version 330\n"
"\n"
"bool _TMP2;\n"
"bvec2 _TMP1;\n"
"vec2 _TMP3;\n"
"uniform vec2 cLensCenter;\n"
"uniform vec2 cScreenCenter;\n"
"uniform vec2 cScale;\n"
"uniform vec2 cScaleIn;\n"
"uniform vec4 cHmdWarpParam;\n"
"uniform sampler2D nlTex0;\n"
"vec2 _TMP10;\n"
"vec2 _b0011;\n"
"vec2 _a0011;\n"
"in vec4 nlTexCoord0;\n"
"out vec4 nlCol;\n"
"\n"
"void main()\n"
"{\n"
" vec2 _theta;\n"
" float _rSq;\n"
" vec2 _theta1;\n"
" vec2 _tc;\n"
"\n"
" _theta = (nlTexCoord0.xy - cLensCenter)*cScaleIn;\n"
" _rSq = _theta.x*_theta.x + _theta.y*_theta.y;\n"
" _theta1 = _theta*(cHmdWarpParam.x + cHmdWarpParam.y*_rSq + cHmdWarpParam.z*_rSq*_rSq + cHmdWarpParam.w*_rSq*_rSq*_rSq);\n"
" _tc = cLensCenter + cScale*_theta1;\n"
" _a0011 = cScreenCenter - vec2( 0.25, 0.5);\n"
" _b0011 = cScreenCenter + vec2( 0.25, 0.5);\n"
" _TMP3 = min(_b0011, _tc);\n"
" _TMP10 = max(_a0011, _TMP3);\n"
" _TMP1 = bvec2(_TMP10.x == _tc.x, _TMP10.y == _tc.y);\n"
" _TMP2 = _TMP1.x && _TMP1.y;\n"
" if (!_TMP2) {\n"
" nlCol = vec4(0, 0, 0, 0);\n"
" } else {\n"
" nlCol = texture(nlTex0, _tc);\n"
" }\n"
"}\n";
}
/* end of file */ /* end of file */

View file

@ -616,10 +616,16 @@ void initStereoDisplayDevice()
std::vector<NL3D::CStereoDeviceInfo> devices; std::vector<NL3D::CStereoDeviceInfo> devices;
listStereoDisplayDevices(devices); listStereoDisplayDevices(devices);
CStereoDeviceInfo *deviceInfo = NULL; CStereoDeviceInfo *deviceInfo = NULL;
if (ClientCfg.VRDisplayDevice == std::string("Auto") if (ClientCfg.VRDisplayDevice == std::string("Auto"))
&& devices.begin() != devices.end())
{ {
deviceInfo = &devices[0]; for (std::vector<NL3D::CStereoDeviceInfo>::iterator it(devices.begin()), end(devices.end()); it != end; ++it)
{
if ((*it).AllowAuto)
{
deviceInfo = &(*it);
break;
}
}
} }
else else
{ {