1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
<!-- HTML header for doxygen 1.8.12-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.11"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>NVIDIAGeForceExperienceSDK: Development Guide</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
$(document).ready(function() { init_search(); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="customdoxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">NVIDIAGeForceExperienceSDK
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.11 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<div id="navrow1" class="tabs">
<ul class="tablist">
<li class="current"><a href="index.html"><span>Main Page</span></a></li>
<li><a href="pages.html"><span>Related Pages</span></a></li>
<li><a href="annotated.html"><span>Classes</span></a></li>
<li><a href="files.html"><span>Files</span></a></li>
<li>
<div id="MSearchBox" class="MSearchBoxInactive">
<span class="left">
<img id="MSearchSelect" src="search/mag_sel.png"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
alt=""/>
<input type="text" id="MSearchField" value="Search" accesskey="S"
onfocus="searchBox.OnSearchFieldFocus(true)"
onblur="searchBox.OnSearchFieldFocus(false)"
onkeyup="searchBox.OnSearchFieldChange(event)"/>
</span><span class="right">
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
</span>
</div>
</li>
</ul>
</div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('index.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="header">
<div class="headertitle">
<div class="title">Development Guide </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>Creation and destruction of an SDK instance is a prerequisite to making calls to the SDK. The means of creating and destroying an instance depend on which integration mechanism the client employs:</p>
<p>See <a class="el" href="isdk_8h.html">Core header documentation</a></p>
<p>See <a class="el" href="ihighlights_8h.html">Highlights header documentation</a></p>
<h4>C++ Bindings</h4>
<div class="fragment"></div><!-- fragment --><p> // After using GfeSDK</p>
<div class="fragment"></div><!-- fragment --> <h4>C API</h4>
<div class="fragment"></div><!-- fragment --><p> // After using GfeSDK</p>
<div class="fragment"></div><!-- fragment --> <p>The Create call will inform the app if one or more scopes require user permission. If so, make this call. It will display the overlay UI.</p>
<h4>C++ Bindings</h4>
<div class="fragment"></div><!-- fragment --> <h4>C API</h4>
<div class="fragment"></div><!-- fragment --> <p>This only needs to happen once ever. It is persistent. It could even happen during game installation.</p>
<h4>C++ Bindings</h4>
<div class="fragment"></div><!-- fragment --> <h4>C API</h4>
<div class="fragment"></div><!-- fragment --> <h4>C++ Bindings</h4>
<div class="fragment"></div><!-- fragment --><div class="fragment"></div><!-- fragment --><div class="fragment"></div><!-- fragment --> <h4>C API</h4>
<div class="fragment"></div><!-- fragment --><div class="fragment"></div><!-- fragment --><div class="fragment"></div><!-- fragment --> <h4>C++ Bindings</h4>
<div class="fragment"></div><!-- fragment --> <h4>C API</h4>
<div class="fragment"></div><!-- fragment --> <p>The GfeSDK is composed of two parts, the client/app, and the backend/server. This distribution contains GfeSDK.dll which represents the client/app part. The end-user downloads GFE onto their machine. The GFE package includes the backend pieces necessary to support the calls coming from the client. See <a class="el" href="index.html#section_version">Versioning</a> for more information regarding this communication.</p>
<p>Calls made will be serialized. Therefore, if the app makes two consecutive calls to NVGSDK_Highlights_OpenGroup and then either NVGSDK_Highlights_SetVideoHighlight or NVGSDK_Highlights_SetScreenshotHighlight, before receiving the callback from open group, the set highlight call will function normally. If open group succeeded, then the set highlights calls will succeed as well. If it failed, the set highlights calls will fail, as there will be no valid group to assign them to.</p>
<p>All strings are to be provided in single-byte width, UTF-8 encoded.</p>
<p>Because there are two different parts, and the client / user's machine may be mismatched at times, the game should be aware of the versioning system. It's GfeSDK's goal to make this as seamless as possible, but there could still be compatibility issues to be aware of.</p>
<p>The GfeSDK version contains 4 parts, MAJOR.MINOR.BUILD.HASH. The BUILD and HASH components are descriptive and don't have any effect on functionality. The MAJOR component identifies overall compatibility. If the client and server mismatch on the major version number, no communication is possible. <b>There are no current plans to update from 1, breaking communication</b>. The major version number gives a way to show incompatibility if the fundamental architecture of GFE ever changes. The minor version number indicates feature compatibility. When a new feature gets added / modified on the SDK, the minor version number will be bumped. This means that for older games / newer GFE installations, the game is simply missing out on newer features. This will generally not be a problem. For a game with a newer version of the GfeSDK, and a user with an older installation of GFE, some features may not function, and the user should be encouraged to update GFE.</p>
<p>With that in mind, here are the possible return values from <a class="el" href="isdk_8h.html#a95b3999b5808922e29a36375c22014b8">NVGSDK_Create</a>, with regards to versioning:</p><ul>
<li><b>NVGSDK_SUCCESS</b> - Perfect version match</li>
<li><b>NVGSDK_SUCCESS_OLD_GFE</b> - Minor version mismatch. User has an older version of GFE installed. Newer features distributed by the game will not function properly until the user upgrades.</li>
<li><b>NVGSDK_SUCCESS_OLD_SDK</b> - Minor version mismatch. Game is distributing an older version of GfeSDK. Game could be missing out on latest features, but no compatibily issue.</li>
<li><b>NVGSDK_ERR_GFE_VERSION</b> - Major version mismatch. User has a GFE installation that predates the GfeSDK. User must upgrade to get functionality.</li>
<li><b>NVGSDK_ERR_SDK_VERSION</b> - Major version mismatch. GFE has changed fundamentally. <b>There are no plans to do this. This is to cover all bases</b></li>
</ul>
<p>Certain actions require permission from the user. For example, recording video for Highlights requires the user to agree to the recording. To achieve this, the app must know what features it wishes to enable. It will pass these "scopes" into the NVGSDK_Create call via <a class="el" href="struct_n_v_g_s_d_k___create_input_params.html">NVGSDK_CreateInputParams</a>. Consider the typical Highlights case as an example. The app will pass in a list of the scopes NVGSDK_SCOPE_HIGHLIGHTS, NVGSDK_SCOPE_HIGHLIGHTS_VIDEO, and NVGSDK_SCOPE_SCREENSHOT. The first of these is required in order for any of the NVGSDK_Highlights_* calls to succeed and send a message to the server. It will allocate the resources required in the DLL and on the server in order to achieve this. The second of these permissions is required in order to capture video of the gameplay, and the final is to capture a screenshot.</p>
<p>The first time the user runs the game, and the game calls NVGSDK_Create(...), and passes in these three permissions, the game might receive back that NVGSDK_SCOPE_HIGHLIGHTS has been granted permission implicitly, but that NVGSDK_SCOPE_HIGHLIGHTS_VIDEO and NVGSDK_SCOPE_HIGHLIGHTS_SCREENSHOT currently have "must ask" permission. In other words, the game must ask GFE for permission to record video before it will succeed in doing so. To achieve this, the game will call NVGSDK_RequestPermissionsAsync with two scopes in the list, NVGSDK_SCOPE_HIGHLIGHTS_VIDEO and NVGSDK_SCOPE_HIGHLIGHTS_SCREENSHOT. It's not necessary to request permission for a scope that has implicitly been granted permission already.</p>
<p>The call to NVGSDK_RequestPermissions is required because it will trigger GFE to put up an <a class="el" href="index.html#section_igo">In Game Overlay</a>. The game might not want this to occur during NVGSDK_Create time. Once called, the user will see the overlay pop up, asking them for permission.</p>
<div class="image">
<img src="permission.png" alt="permission.png"/>
<div class="caption">
Highlights Permission</div></div>
<p> The async callback will be triggered as soon as the message is processed by the GFE backend. The user will be able to accept, deny, or defer the request. If the user accepts or denies the request, the app will recieve a <a class="el" href="sdk__types_8h.html#a41214fdc112a95d5fe8e760b0c562c59ab4d95c5d0180de2ae500c1b33bd0c115">NVGSDK_NOTIFICATION_PERMISSIONS_CHANGED</a> notification with the results. If <a class="el" href="isdk_8h.html#a3e4b6afcafe9ac91c00a95b7d72305e5">NVGSDK_RequestPermissionsAsync</a> is called again when the permission is already granted or denied, the overlay will not be displayed a second time. The user can reverse their decision in either case later on in GFE3 on the games details page.</p>
<p>Most of the calls to GfeSDK are asynchronous. This is due to the client/server architecture described in <a class="el" href="index.html#section_concepts">Concepts</a>. For each asynchronous call, a callback and an opaque void* context are passed in as arguments. If the app does not care or desire to know what happens to the call, is it fine to pass in NULL. If the app does care, supply a callback of the proper type, and optionally a pointer as a context to receive back during the callback.</p>
<p>The callbacks are properly typed. For callbacks that return nothing but the return value and context, a <a class="el" href="sdk__types_8h.html#a1c5cd84ed88c70462c360a7268eb95ac">NVGSDK_EmptyCallback</a> is passed in. For versions that do return data, a typed callback is passed in, such as <a class="el" href="sdk__types_8h.html#aa327c1a78bd452bd8edbcad7a4e4d86a">NVGSDK_GetUILanguageCallback</a>.</p>
<p>The callback will be called on one of three threads, depending on the situation. If <a class="el" href="struct_n_v_g_s_d_k___create_input_params.html#a0bd7568c1cb3fad975562055b4581195" title="Set to true to poll for asynchronous callbacks on an app thread. If false, callbacks will occur on a ...">NVGSDK_CreateInputParams::pollForCallbacks</a> is set to false during creation, the callback will always occur on a GfeSDK controller thread. If the app desires callback to occur on their own thread, true is passed in instead. In that case, the callback will occur on the thread that calls <a class="el" href="isdk_8h.html#af5beaa7808f8dfc4660f5a0d4f8bccb3">NVGSDK_Poll</a>. The exception is that during NVGSDK_Destroy, GfeSDK pushes out all remaining callbacks. If the app is awaiting any callbacks during this time, they will be called on the same thread that called NVGSDK_Destroy. Usually, this will be the same thread that calls NVGSDK_Poll, so it shouldn't cause any surprises, but it's something to be aware of. See <a class="el" href="index.html#section_threading">Threading</a> for more information</p>
<div class="fragment"></div><!-- fragment --><div class="fragment"></div><!-- fragment --><p> <b>Note:</b> There is currently a limitation in the GfeSDK backend that depends on game frames being rendered during certain API calls. Therefore, the game cannot block the render loop while awaiting an asynchronous callback. Doing so will result in a deadlock.</p>
<p>In addition to the async callbacks that most of the APIs accept as an argument, the app can also register to recieve unsolicited notifications when certain events occur. For example, the app might want to know when the user can given / removed permission for recording video from the app, either through the permissions dialog, or via GFE3. See <a class="el" href="struct_n_v_g_s_d_k___create_input_params.html">NVGSDK_CreateInputParams</a> and <a class="el" href="sdk__types_8h.html#a41214fdc112a95d5fe8e760b0c562c59">NVGSDK_NotificationType</a></p>
<p>This notification will get called on either the GfeSDK callback thread, or the thread that calls <a class="el" href="isdk_8h.html#af5beaa7808f8dfc4660f5a0d4f8bccb3">NVGSDK_Poll</a>, depending on params passed in to <a class="el" href="isdk_8h.html#a95b3999b5808922e29a36375c22014b8">NVGSDK_Create</a>. See <a class="el" href="index.html#section_threading">Threading</a> for more information.</p>
<p>There are two different threading models that may be used. The model used depends on the value passed in to <a class="el" href="struct_n_v_g_s_d_k___create_input_params.html">NVGSDK_CreateInputParams</a></p>
<h5>GfeSDK Controller Callback Model</h5>
<p>In this model, all callbacks will occur as soon as they are processed on the internal GfeSDK callback thread.</p>
<h5>Polling Model</h5>
<p>The app can choose to use this model if it wants to take action during the callback that depend on being on the game loop. Callbacks are queued up, and executed when the app calls <a class="el" href="isdk_8h.html#af5beaa7808f8dfc4660f5a0d4f8bccb3">NVGSDK_Poll</a>. This means that callbacks will be blocked indefinitely if that API is never called.</p>
<p>The exception occurs during NVGSDK_Destroy. Because the normal case is to make NVGSDK_Destroy and NVGSDK_Poll calls from the same thread, GfeSDK can't block and wait for another poll call. All remaining callbacks will be executed during NVGSDK_Destroy. See <a class="el" href="index.html#section_async">Asynchronous Calls</a> for more info.</p>
<div class="image">
<img src="igo.png" alt="igo.png"/>
<div class="caption">
In Game Overlay</div></div>
<p> The In-Game overlay can be used by the user to change Highlights settings, and view Highlights that have been saved to the gallery. It's also used to display the permissions dialog from <a class="el" href="isdk_8h.html#a3e4b6afcafe9ac91c00a95b7d72305e5">NVGSDK_RequestPermissionsAsync</a>, and the group summary from NVGSDK_OpenGroupSummaryAsync. The user can open it up by themselves using the default keybinding Alt+Z</p>
<h3>Highlights Summary</h3>
<p>Many times a button is used to display the Highlights Summary. Suggested UX: "View \%d highlights" or "\%d new highlights". Include an icon to the left of the text. The icon to use is located in GfeSDK/redist/assets/img/img_logo_experience_512.png</p>
<p>By default, GfeSDK stores its own logs for problem triage in %LOCALAPPDATA%\NVIDIA Corporation\GfeSDK. This behavior can be adjusted by the following calls:</p>
<ul>
<li><a class="el" href="isdk_8h.html#a823df4f563527040a016bab8298869c5">NVGSDK_SetLogLevel</a></li>
<li><a class="el" href="isdk_8h.html#afc7b2b775f0ffaf80b2b5a988c4d6d11">NVGSDK_AttachLogListener</a></li>
<li><a class="el" href="isdk_8h.html#a742af01ab93d41b3aa9579df90c6c00f">NVGSDK_SetListenerLogLevel</a> </li>
</ul>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.8.12-->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated by
<a href="http://www.doxygen.org/index.html">
doxygen</a> 1.8.11 </li>
</ul>
</div>
</body>
</html>
|