--- /dev/null
+
+<!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" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=9" />
+ <link rel="stylesheet" type="text/css" href="../../css/styles.css" />
+ <link rel="stylesheet" type="text/css" href="../../css/snippet.css" />
+ <script type="text/javascript" src="../../scripts/snippet.js"></script>
+ <script type="text/javascript" src="../../scripts/jquery.util.js" charset="utf-8"></script>
+ <script type="text/javascript" src="../../scripts/common.js" charset="utf-8"></script>
+ <script type="text/javascript" src="../../scripts/core.js" charset="utf-8"></script>
+ <script type="text/javascript" src="../../scripts/search.js" charset="utf-8"></script>
+ <title>SDL Graphics with Vulkan</title>
+ </head>
+ <body onload="prettyPrint()" style="overflow: auto;">
+
+ <div id="toc-navigation">
+ <div id="profile">
+ <p><img alt="Mobile native" src="../../images/mobile_s_n.png"/></p>
+ </div>
+
+ <div id="toc_border"><div id="toc">
+ <p class="toc-title">Dependencies</p>
+ <ul class="toc">
+ <li>Tizen 3.0 and Higher for Mobile</li>
+ </ul>
+ <p class="toc-title">Content</p>
+ <ul class="toc">
+ <li><a href="#vulkan_1">OpenGL vs. Vulkan</a></li>
+ <li><a href="#sdl">SDL</a></li>
+ <li><a href="#prerequisites">Prerequisites</a></li>
+ <li><a href="#render">Rendering a Triangle with Vulkan</a></li>
+ <li><a href="#SDL_event">Handling General SDL Events</a></li>
+ <li><a href="#tizen_event">Handling Tizen-specific SDL Events</a></li>
+ </ul>
+ <p class="toc-title">Related Info</p>
+ <ul class="toc">
+ <li><a href="../../../../org.tizen.native.mobile.apireference/group__OPENSRC__VULKAN__FRAMEWORK.html">Vulkan API for Mobile Native</a></li>
+ </ul>
+ </div></div>
+</div>
+
+<div id="container"><div id="contents"><div class="content">
+
+<h1>SDL Graphics with Vulkan</h1>
+
+<p>Vulkan is a generation API for high-efficiency access to graphics and computing on modern GPUs. It is an open-standard, cross-platform API designed from the ground-up by industry experts collaborating under the Khronos consortium. It aims to address the inefficiencies of existing 3D APIs, such as OpenGL, which are designed for single-core processors and lag to map modern hardware. It provides a much lower-level fine-grained control over the GPU to maximize performance and achieve consistent user experience across different operating environments. For general information on Vulkan, and the comparative merits of Vulkan and OpenGL, see the official Khronos's <a href="https://www.khronos.org/vulkan/" target="_blank">Vulkan Web site</a> and <a href="#vulkan_1">OpenGL vs. Vulkan</a>.</p>
+<p>The Tizen platform supports the Vulkan API in order to provide the most cutting edge 3D programming tools for you to create high-quality games and real-time graphics in applications. Vulkan is especially recommended for performance- or latency-sensitive applications. With Vulkan, you can achieve a much smoother user experience by parallelizing the rendering job across multiple threads which can feed the GPU to the max. Applications demanding explicit control on work submission, synchronization, and less power consumption can seriously consider migrating to Vulkan as well. Tizen allows the <a href="#render">use of the Vulkan API</a> through <a href="#sdl">SDL</a>.</p>
+
+<p class="figure">Figure: Vulkan in Tizen</p>
+<p align="center"><img alt="SDL logo" src="../../images/vulkan_framework.png" /></p>
+
+<p>Before using the Vulkan API in Tizen, make sure that you are familiar with the following key Vulkan features, which help you to align your application design around Vulkan concepts and exploit the hardware to the fullest:</p>
+
+<ul>
+<li><strong>Cross-platform</strong>
+<p>Vulkan is designed to run on a wide range of platforms and hardware with very different form factors and power envelopes. While OpenGL has the OpenGL ES variant for mobile and embedded systems and OpenGL for desktops, Vulkan provides a unified API that is completely identical across all these platforms. You simply link to the same library, with the same header and the same code on all targeted platforms, and the application runs everywhere. By not limiting itself to a subset of platforms, Vulkan enables you to "write once and run everywhere". This means that by targeting this API, you can achieve a large market share across both mobile and desktop devices.</p></li>
+
+<li><strong>Explicit control</strong>
+<p>Vulkan is an explicit API, and wants you to define "exactly what you want", rather than relying on hidden driver heuristics to do the right thing. Vulkan, by design, is a very low-level API that provides applications direct control over the GPU. Older higher-level APIs hide most of the costly operations, such as memory management and resource synchronization, denying you any control over them.</p>
+<p>Vulkan attempts to turn as much of the problematic "implicitness" of older APIs as possible into "explicit" application choices. It provides a number of explicit mechanisms for many operations, such as memory allocation, synchronization, and work submission, allowing applications to be more expressive.</p></li>
+
+<li><strong>Multi-core friendly</strong>
+<p>Older APIs written in the single-core processor age do not do enough to take advantage of today's multi-core processors and thereby max out the single core by over-burdening the render thread with all heavy tasks, such as error checking, implicit resource tracking, synchronization, and state validation.</p>
+<p>Vulkan provides tools and design choices to spread its workload across multiple threads. It achieves this by removing from the driver the thread-specific features, such as global data, access synchronization, thread safety, and order guarantee, and handing the responsibility to you. By carefully handling the threads and scaling across multiple threads on a device with more cores, you can distribute your workload across threads much better. This leads to better efficiency and better performance in applications that otherwise find themselves maxing out a single core.</p></li>
+
+<li><strong>High efficiency</strong>
+<p>With a better design, Vulkan offers the potential to reduce the workload of the render thread and thereby allows the application to draw less power and generate less heat. It achieves better throughput by removing lots of (mostly) unnecessary background work, such as runtime error checking, state validation, and shader compilation, from the main loop. It delegates that background work to the tooling and layers, which are used during development and get removed before the application makes it to a consumer device.</p></li>
+
+<li><strong>Portable</strong>
+<p>With the introduction of an intermediate shader language, called SPIR-V, Vulkan improves the shader program portability and allows you to write shaders in languages other than GLSL (such as C/C++). This avoids the need for the compiler to execute during runtime to translate the shader code and allows offline shader precompilation. It also relieves the vendors from the shader/kernel source shipping and IP leakage.</p></li>
+</ul>
+
+<h2 id="vulkan_1">OpenGL vs. Vulkan</h2>
+
+<p>When you consider the differences and advantages between Vulkan and OpenGL, Vulkan basically compliments OpenGL by addressing specific users who want to have a quite low-level API with a much better abstraction of the modern hardware giving a lot of control, predictability, and high performance at much greater efficiency. On the other hand, OpenGL is a much higher-level API that does many things on your behalf inside the driver with less burden on you. It continues to be the API of choice for a wide range of developers who want to have the shortest path to a functionally correct application.</p>
+
+<p>When selecting the open graphics API (Vulkan or OpenGL) to use for a new application, or when considering the need to migrate an existing application from OpenGL to Vulkan, ask yourself the following questions:</p>
+<ul>
+<li>Do you want to have really low-level access and explicit control over the underlying GPU?</li>
+<li>Is your application/driver CPU-bound, too slow and consuming too much power?</li>
+<li>Can your graphic work creation be parallelized and reused?</li>
+<li>Can you deal with additional code complexity to squeeze out maximum performance?</li>
+</ul>
+<p>If your answer to any of the questions is <strong>Yes</strong>, consider using Vulkan instead of OpenGL. However, remember that Vulkan comes at the cost of taking more responsibility at the application side from the driver.</p>
+
+<p>The following table describes the practical advantages of Vulkan.</p>
+
+<p align="center" class="Table"><strong>Table: Vulkan advantages</strong></p>
+<table>
+<tbody>
+<tr>
+ <th></th>
+ <th>OpenGL</th>
+ <th>Vulkan</th>
+</tr>
+<tr>
+ <th>Better GPU control</th>
+ <td>Implicit driver manages the state and resources based on heuristics, leading to overhead and inefficiencies. The application has <strong>no control</strong>.</td>
+ <td>Explicit API allows you to manage the state and resources as per specific application needs, and relieves you from hidden optimizations giving more control on the GPU.</td>
+</tr>
+<tr>
+ <th>Multi-core friendly</th>
+ <td>Originally designed for single-threaded architectures and does not allow the generation of graphic commands in parallel to command execution.</td>
+ <td>API is designed around asynchronous generation of command buffers across multiple threads and feeds them in sequence to a command pipeline, which reflects the realities of the modern hardware.</td>
+</tr>
+<tr>
+ <th>High efficiency</th>
+ <td>Does a lot of redundant excessive validation for each draw call, such as runtime error checking, implicit tracking of resource usage, and synchronization, leading to much CPU overhead.</td>
+ <td>Vulkan greatly reduces the CPU time spent in the driver with external validation and diagnostics layers that can be independently enabled and disabled, as needed. Offloads the render thread by delegating heavy CPU jobs to the application and opt-in layers.</td>
+</tr>
+<tr>
+ <th>Shader portability</th>
+ <td>Only GLSL is supported as a shader language, and the compiler is a part of the driver with vendor-specific semantics. No user control over the front end and higher runtime translation time.</td>
+ <td>Vulkan mandates the use of the intermediate byte code (SPIR-V) by the driver for shaders. This allows offline shader precompilation, and allows you to write shaders in languages other than GLSL.</td>
+</tr>
+<tr>
+ <th>Code complexity</th>
+ <td>OpenGL driver manages many tasks inside the driver relieving you from the burden of managing these at the application end.</td>
+ <td>Vulkan is a much more verbose API, offering more control at the cost of more code complexity and responsibility at the application side.</td>
+</tr>
+</tbody>
+</table>
+
+<h2 id="sdl">SDL</h2>
+
+<p>SDL (Simple DirectMedia Layer) is a cross-platform software development library. In Tizen, it enables access to graphics hardware using Vulkan. SDL is used for creating high-performance computer games, multimedia applications, and emulators. It provides a low-level hardware abstraction layer to computer multimedia hardware components. It can run on many operating systems, such as Android, iOS, Linux, Mac OS X, Windows, and Tizen. For more information, see the <a href="https://libsdl.org/" target="_blank">SDL Web site</a>.</p>
+
+<p>You can manage video, audio, some input devices, threads, and timers with SDL. Tizen supports SDL to provide new means of accessing its 3D APIs (Vulkan), which can currently be accessed only through an EFL wrapper library (Evas GL). For more information on Evas GL, see the <a href="../graphics/opengl_n.htm">OpenGL ES</a> guide.</p>
+
+<p>The following SDL features are currently supported in Tizen:</p>
+<ul>
+<li>SDL basics function
+<p>Use the <span style="font-family: Courier New,Courier,monospace">SDL.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_hints.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_error.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_log.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_assert.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_version.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_error.h</span>, and <span style="font-family: Courier New,Courier,monospace">SDL_stdinc.h</span> header files.</p></li>
+<li>Display and window management
+<p>Use the <span style="font-family: Courier New,Courier,monospace">SDL_video.h</span> and <span style="font-family: Courier New,Courier,monospace">SDL_syswm.h</span> header files.</p></li>
+<li>Event handling
+<p>Use the <span style="font-family: Courier New,Courier,monospace">SDL_events.h</span> and <span style="font-family: Courier New,Courier,monospace">SDL_keyboard.h</span> header files.</p></li>
+<li>Audio device management
+<p>Use the <span style="font-family: Courier New,Courier,monospace">SDL_audio.h</span> header file.</p></li>
+<li>Thread and timer management
+<p>Use the <span style="font-family: Courier New,Courier,monospace">SDL_thread.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_mutex.h</span>, <span style="font-family: Courier New,Courier,monospace">SDL_atomic.h</span>, and <span style="font-family: Courier New,Courier,monospace">SDL_timer.h</span> header files.</p></li>
+<li>Platform and power information
+<p>Use the <span style="font-family: Courier New,Courier,monospace">SDL_platform.h</span> and <span style="font-family: Courier New,Courier,monospace">SDL_power.h</span> header files.</p></li>
+</ul>
+<p>For the list of features not currently supported in Tizen, see the <a href="../../../../org.tizen.native.mobile.apireference/group__OPENSRC__SDL__FRAMEWORK.html">SDL API reference.</a></p>
+
+<h3 id="lifecycle">SDL Application Life-cycle in Tizen</h3>
+
+<p>The Tizen native application model is responsible for the application life-cycle and system events. The SDL application life-cycle is handled by the <span style="font-family: Courier New,Courier,monospace">SDL_PollEvent()</span> function, which manages the main event loop, the application state change events, and basic system events (<a href="#SDL_event">general</a> and <a href="#tizen_event">Tizen-specific</a>).</p>
+
+<p class="figure">Figure: SDL life-cycle</p>
+<p align="center"><img alt="SDL life-cycle" src="../../images/sdl_statemodel.png" /></p>
+
+<p>The SDL application can be in one of several different states, and the state changes are managed by the underlying framework.</p>
+
+<p align="center" class="Table"><strong>Table: SDL application states</strong></p>
+<table>
+<tbody>
+<tr>
+ <th>State</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td>READY</td>
+ <td>Application starts the main loop.</td>
+</tr>
+<tr>
+ <td>CREATED</td>
+ <td>Application is launched.</td>
+</tr>
+<tr>
+ <td>RUNNING</td>
+ <td>Application is running and visible to the user.</td>
+</tr>
+<tr>
+ <td>PAUSED</td>
+ <td>Application is running but invisible to the user.</td>
+</tr>
+<tr>
+ <td>TERMINATED</td>
+ <td>Application is terminated.</td>
+</tr>
+</tbody>
+</table>
+
+
+<p>Typically, the application is launched by the user from the Launcher, or by another application. The application is normally launched as the top window, with focus. When the application loses the focus status, the <span style="font-family: Courier New,Courier,monospace">SDL_APP_WILLENTERBACKGROUND</span> and <span style="font-family: Courier New,Courier,monospace">SDL_APP_DIDENTERBACKGROUND</span> events are invoked. The application can go into the pause state, which means that it is not terminated but continues to run on the background. The pause state can happen when:</p>
+<ul>
+<li>A new application is launched based on a request from your application.</li>
+<li>The user requests to go to the home screen.</li>
+<li>A system event (such as an incoming phone call) occurs and causes a resident application with a higher priority to become active and temporarily hide your application.</li>
+<li>An alarm is triggered for another application, which becomes the topmost window and hides your application.</li>
+</ul>
+
+<p>When the application becomes visible again, the <span style="font-family: Courier New,Courier,monospace">SDL_APP_WILLENTERFOREGROUND</span> and <span style="font-family: Courier New,Courier,monospace">SDL_APP_DIDENTERFOREGROUND</span> events are invoked. The visibility returns, when:</p>
+<ul>
+<li>Another application requests your application to run (such as the Task Navigator, which shows all running applications and lets user select any application to run).</li>
+<li>All applications on top of your application in the window stack finish.</li>
+<li>An alarm is triggered for your application, bringing it to the front and hiding other applications.</li>
+</ul>
+
+<p>When the application starts exiting, the <span style="font-family: Courier New,Courier,monospace">SDL_Quit</span> and <span style="font-family: Courier New,Courier,monospace">SDL_TERMINATING</span> events are invoked. Your application can start the termination process, when:</p>
+<ul>
+<li>The application itself requests to exit by calling the <span style="font-family: Courier New,Courier,monospace">ui_app_exit()</span> or <span style="font-family: Courier New,Courier,monospace">service_app_exit()</span> function to terminate the event loop.</li>
+<li>The low memory killer is terminating your application in a low memory situation.</li>
+</ul>
+
+
+<h2 id="prerequisites">Prerequisites</h2>
+
+<p>To enable your application to use the Vulkan functionality:</p>
+<ol>
+<li>To use Vulkan for 3D rendering, you must create an SDL application, and understand both <a href="https://www.khronos.org/vulkan/" target="blank">Vulkan</a> and <a href="https://www.libsdl.org/" target="blank">SDL</a>.
+</li>
+
+<li>Check whether the device supports Vulkan.
+<p>As all Tizen devices available in the market do not support Vulkan yet, check the device support with the <span style="font-family: Courier New,Courier,monospace">system_info_get_platform_bool()</span> function before using the Vulkan APIs. If the device can support Vulkan, the function returns <span style="font-family: Courier New,Courier,monospace">true</span> in the second parameter.</p>
+<pre class="prettyprint">
+bool vulkan_support;
+
+system_info_get_platform_bool("http://tizen.org/feature/vulkan.version.1_0", &vulkan_support);
+</pre>
+</li>
+<li>To use the functions and data types of the <a href="../../../../org.tizen.native.mobile.apireference/group__OPENSRC__VULKAN__FRAMEWORK.html">Vulkan</a> and <a href="../../../../org.tizen.native.mobile.apireference/group__OPENSRC__SDL__FRAMEWORK.html">SDL</a> APIs, include the <span style="font-family: Courier New,Courier,monospace"><SDL.h></span> and <span style="font-family: Courier New,Courier,monospace"><vulkan/vulkan.h></span> header files in your application:
+<pre class="prettyprint">
+#include <SDL.h>
+#include <vulkan/vulkan.h>
+</pre>
+</li>
+</ol>
+
+<h2 id="render">Rendering a Triangle with Vulkan</h2>
+
+<p>To render a triangle using Vulkan in an SDL application:</p>
+
+<ol>
+<li>Initialize SDL and create an SDL window.
+
+<p>Before using any other SDL functions, call the <span style="font-family: Courier New,Courier,monospace">SDL_Init()</span> function to properly initialize the SDL library and start each of its various subsystems. The function accepts as a parameter a set of allowed flags OR'd together.</p>
+<p>After SDL is initialized successfully, create the <span style="font-family: Courier New,Courier,monospace">SDL_Window</span> instance using the <span style="font-family: Courier New,Courier,monospace">SDL_CreateWindow()</span> function. The parameters define the title of the window, the X and Y position coordinates, width, height, and a set of <span style="font-family: Courier New,Courier,monospace">SDL_WindowFlags</span> OR'd together.</p>
+
+ <table class="note">
+ <tbody>
+ <tr>
+ <th class="note">Note</th>
+ </tr>
+ <tr>
+ <td class="note">To use the Vulkan context, use the <span style="font-family: Courier New,Courier,monospace">SDL_WINDOW_VULKAN</span> flag when you create a window. Do not use both <span style="font-family: Courier New,Courier,monospace">SDL_WINDOW_VULKAN</span> and <span style="font-family: Courier New,Courier,monospace">SDL_WINDOW_OPENGL</span> simultaneously.</td>
+ </tr>
+ </tbody>
+ </table>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">SDL_main()</span> function is mandatory for the Tizen framework to initialize the SDL application. You must use the <span style="font-family: Courier New,Courier,monospace">SDL_main()</span> function instead of the usual <span style="font-family: Courier New,Courier,monospace">main()</span> function in your SDL application.</p>
+
+<pre class="prettyprint">
+int
+SDL_main(int argc, char *argv[])
+{
+ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
+ demo.sdl_window = SDL_CreateWindow("SDL Vulkan Sample", 0, 0, demo.sdl_mode.w, demo.sdl_mode.h,
+ SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_VULKAN);
+}
+</pre>
+</li>
+<li>Initialize Vulkan.
+<p>Create a Vulkan instance, which is the connection between the application and the Vulkan library. To create an instance:</p>
+
+<ol type="a">
+<li>Fill in a <span style="font-family: Courier New,Courier,monospace">VkApplicationInfo</span> struct with some information about the application:
+
+<ul>
+<li><span style="font-family: Courier New,Courier,monospace">sType</span> specifies the type of the structure. Most Vulkan structs require you to explicitly specify the structure type in the <span style="font-family: Courier New,Courier,monospace">sType</span> member.</li>
+<li><span style="font-family: Courier New,Courier,monospace">pNext</span> can point to extension information in the future, but currently leave it <span style="font-family: Courier New,Courier,monospace">NULL</span> for the default initialization.</li>
+<li><span style="font-family: Courier New,Courier,monospace">pApplicationName</span> points to a string containing the application name.</li>
+<li><span style="font-family: Courier New,Courier,monospace">applicationVersion</span> contains developer-supplied version number of the application.</li>
+<li><span style="font-family: Courier New,Courier,monospace">pEngineName</span> is a pointer to a string containing the name of the engine (if any) used to create the application.</li>
+<li><span style="font-family: Courier New,Courier,monospace">engineVersion</span> is an unsigned integer variable containing the developer-supplied version number of the engine used to create the application.</li>
+<li><span style="font-family: Courier New,Courier,monospace">apiVersion</span> is the version of the Vulkan API against which the application expects to run.</li>
+</ul>
+
+<pre class="prettyprint">
+const VkApplicationInfo app = {
+ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ .pNext = NULL,
+ .pApplicationName = APP_SHORT_NAME,
+ .applicationVersion = 0,
+ .pEngineName = APP_SHORT_NAME,
+ .engineVersion = 0,
+ .apiVersion = VK_API_VERSION_1_0,
+};
+</pre>
+</li>
+
+<li>Vulkan is a platform-agnostic API, which means that you need an extension to interface with the window system. The <span style="font-family: Courier New,Courier,monospace">SDL_Vulkan_GetInstanceExtensions()</span> SDL function returns the extensions Vulkan needs to interface with the windowing system. Pass them to the <span style="font-family: Courier New,Courier,monospace">VkInstanceCreateInfo</span> struct.
+
+<p>Fill in the <span style="font-family: Courier New,Courier,monospace">VkInstanceCreateInfo</span> struct to provide sufficient information for creating an instance. This struct tells the Vulkan driver which global extensions and validation layers you want to use. Global means that they apply to the entire program and not only a specific device.</p>
+
+<ul>
+<li><span style="font-family: Courier New,Courier,monospace">sType</span> and <span style="font-family: Courier New,Courier,monospace">pNext</span> are similar to the <span style="font-family: Courier New,Courier,monospace">VkApplicationInfo</span> structure.</li>
+<li><span style="font-family: Courier New,Courier,monospace">enabledLayerCount</span> is the number of global layers to enable.</li>
+<li><span style="font-family: Courier New,Courier,monospace">ppEnabledLayerNames</span> is a pointer to an array containing the names of layers to enable for the created instance.</li>
+<li><span style="font-family: Courier New,Courier,monospace">enabledExtensionCount</span> is the number of global extensions to enable.</li>
+<li><span style="font-family: Courier New,Courier,monospace">ppEnabledExtensionNames</span> is a pointer to an array of strings containing the names of extensions to enable.</li>
+</ul>
+
+<pre class="prettyprint">
+SDL_Vulkan_GetInstanceExtensions(demo->sdl_window, &(demo->enabled_extension_count), demo->extension_names);
+VkInstanceCreateInfo inst_info = {
+ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ .pNext = NULL,
+ .pApplicationInfo = &app,
+ .enabledLayerCount = demo->enabled_layer_count,
+ .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
+ .enabledExtensionCount = demo->enabled_extension_count,
+ .ppEnabledExtensionNames = (const char *const *) demo->extension_names,
+};
+</pre>
+</li>
+<li>Call the <span style="font-family: Courier New,Courier,monospace">vkCreateInstance()</span> function to actually create the instance:
+
+<pre class="prettyprint">
+vkCreateInstance(&inst_info, NULL, &demo->inst);
+</pre>
+
+<p>The general pattern that object creation function parameters in Vulkan follow is:</p>
+
+<ul>
+<li>Pointer to the struct with the creation info</li>
+<li>Pointer to the custom allocator callbacks</li>
+<li>Pointer to the variable that stores the handle to the new object</li>
+</ul>
+<p>On success, the handle to the instance is returned in the wrapped <span style="font-family: Courier New,Courier,monospace">VkInstance</span> member.</p>
+</li></ol>
+</li>
+<li>Select a physical device.
+<p>After creating a Vulkan instance, look for and select a graphics card in the system that supports the features you need. You can select any number of graphics cards and use them simultaneously, but the following example only selects the first graphics card. The selected graphics card is stored in a <span style="font-family: Courier New,Courier,monospace">VkPhysicalDevice</span> handle.</p>
+<p>Retrieve the list the graphics cards, store them in an array of the <span style="font-family: Courier New,Courier,monospace">VkPhysicalDevice</span> handles, and select the first graphics card as the physical device:</p>
+<pre class="prettyprint">
+VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
+err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
+demo->gpu = physical_devices[0];
+</pre>
+</li>
+<li>Check for supported queue families.
+<p>Almost every operation in Vulkan, from drawing to uploading textures, requires commands to be submitted to a "queue". There are different types of queues that originate from different queue families, and each queue family allows only a subset of commands. You need to check which queue families are supported by the device and which one of them supports the commands that you want to use. The following example looks for a queue that supports graphics commands:</p>
+<ol type="a">
+<li>Check which queue families are supported by the device with the <span style="font-family: Courier New,Courier,monospace">vkGetPhysicalDeviceQueueFamilyProperties()</span> function:
+<pre class="prettyprint">
+VkQueueFamilyProperties *queue_props;
+vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, demo->queue_props);
+assert(demo->queue_count >= 1);
+
+VkPhysicalDeviceFeatures features;
+vkGetPhysicalDeviceFeatures(demo->gpu, &features);
+</pre>
+</li>
+<li>The <span style="font-family: Courier New,Courier,monospace">VkQueueFamilyProperties</span> struct contains details about the queue family, including the type of operations that are supported and the number of queues that can be created based on that family. Look for at least 1 queue family that supports <span style="font-family: Courier New,Courier,monospace">VK_QUEUE_GRAPHICS_BIT</span>:
+<pre class="prettyprint">
+uint32_t graphicsQueueNodeIndex = UINT32_MAX;
+for (i = 0; i < demo->queue_count; i++) {
+ if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
+ if (graphicsQueueNodeIndex == UINT32_MAX)
+ graphicsQueueNodeIndex = i;
+ }
+}
+demo->graphics_queue_node_index = graphicsQueueNodeIndex;
+</pre>
+</li></ol>
+</li>
+<li>Create a logical device.
+<p>After selecting a physical device to use, you need to set up a logical device to interface with it. You can even create multiple logical devices from the same physical device, if you have varying requirements.</p>
+
+<ol type="a">
+<li>Add a new <span style="font-family: Courier New,Courier,monospace">VkDevice</span> type member in which to store the logical device handle:
+<pre class="prettyprint">
+VkDevice device;
+</pre>
+<p>Logical devices are cleaned up with the <span style="font-family: Courier New,Courier,monospace">vkDestroyDevice()</span> function before the instance is cleaned up.</p>
+</li>
+<li>The creation of a logical device involves specifying a lot of details in structs again. First, fill in the <span style="font-family: Courier New,Courier,monospace">VkDeviceQueueCreateInfo</span> struct, which describes the number of queues you want for a single queue family. In the following example, only 1 queue with graphics capabilities is needed.
+<p>The currently available drivers only allow you to create a low number of queues for each family queue, and you do not really need more than one. That is because you can create all of the command buffers on multiple threads and then submit them all at once on the main thread with a single low-overhead call.</p>
+<p>Vulkan lets you assign priorities to queues to influence the scheduling of the command buffer execution using floating point numbers between 0.0 and 1.0. This is required even if there is only a single queue.</p>
+
+<pre class="prettyprint">
+float queue_priorities[1] = {0.0};
+const VkDeviceQueueCreateInfo queue = {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .pNext = NULL,
+ .queueFamilyIndex = demo->graphics_queue_node_index,
+ .queueCount = 1,
+ .pQueuePriorities = queue_priorities
+};
+</pre>
+</li>
+<li>Fill in the main <span style="font-family: Courier New,Courier,monospace">VkDeviceCreateInfo</span> structure.
+<p>First add pointers to the queue creation info and device features structs. The remainder of the information requires you to specify device-specific extensions and validation layers. An example of a device-specific extension is <span style="font-family: Courier New,Courier,monospace">VK_KHR_swapchain</span>, which allows you to present rendered images from that device to windows. The following example enables the same validation layers for devices as before for the instance. It requires no device-specific extensions.</p>
+<pre class="prettyprint">
+VkDeviceCreateInfo device = {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pNext = NULL,
+ .queueCreateInfoCount = 1,
+ .pQueueCreateInfos = &queue,
+ .enabledLayerCount = demo->enabled_layer_count,
+ .ppEnabledLayerNames = (const char *const *)((demo->validate) ? demo->device_validation_layers: NULL),
+ .enabledExtensionCount = demo->enabled_extension_count,
+ .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
+ .pEnabledFeatures = NULL
+};
+</pre>
+</li>
+<li>Instantiate the logical device with the <span style="font-family: Courier New,Courier,monospace">vkCreateDevice()</span> function.
+<p>The parameters are the physical device to interface with, the queue and usage info you just specified, the optional allocation callback pointer, and a pointer to a variable to store the logical device handle in.</p>
+<pre class="prettyprint">
+vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
+</pre>
+</li></ol></li>
+
+<li>Create a window surface.
+<p>Since Vulkan is a platform-agnostic API, it cannot interface directly with the window system on its own. To establish the connection between Vulkan and the window system to present results to the screen, you need to use the WSI (Window System Integration) extensions. The <span style="font-family: Courier New,Courier,monospace">VK_KHR_surface</span> extension exposes a <span style="font-family: Courier New,Courier,monospace">VkSurfaceKHR</span> object that represents an abstract type of surface to present rendered images to. The surface in this example program is backed by the window that you have already created using SDL.</p>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">VK_KHR_surface</span> extension is an instance-level extension and you have actually already enabled it, because it is included in the list returned by the <span style="font-family: Courier New,Courier,monospace"> SDL_Vulkan_GetInstanceExtensions()</span> function. Even though the window surface is created before the logical device in this example, it is only mentioned here after the logical device creation, because window surfaces are part of the render targets and presentation part, and explaining them earlier would have cluttered up the basic setup.</p>
+
+ <table class="note">
+ <tbody>
+ <tr>
+ <th class="note">Note</th>
+ </tr>
+ <tr>
+ <td class="note">Window surfaces are an entirely optional component in Vulkan, if you just need off-screen rendering. Vulkan allows you to do that without hacks, such as creating an invisible window (necessary for OpenGL).</td>
+ </tr>
+ </tbody>
+ </table>
+
+<ol type="a">
+<li>Add a <span style="font-family: Courier New,Courier,monospace">VkSurfaceKHR</span> type variable:
+<pre class="prettyprint">
+VkSurfaceKHR surface;
+</pre>
+<p>When no longer needed, surfaces are destroyed with the <span style="font-family: Courier New,Courier,monospace">vkDestroySurfaceKHR()</span> function.</p>
+</li>
+<li>Although the <span style="font-family: Courier New,Courier,monospace">VkSurfaceKHR</span> object and its usage is platform-agnostic, its creation is not, because it depends on the window system details. Therefore, there is a platform-specific addition to the extension, which on Tizen is <span style="font-family: Courier New,Courier,monospace">SDL_vulkanSurface</span> and is also automatically included in the list from the <span style="font-family: Courier New,Courier,monospace">SDL_Vulkan_GetInstanceExtensions()</span> function.
+<p>This platform-specific extension on Tizen provides the <span style="font-family: Courier New,Courier,monospace">SDL_Vulkan_CreateSurface()</span> function to create a surface hiding the platform differences for you. The parameters are the SDL window pointer, custom allocators, and pointer to the <span style="font-family: Courier New,Courier,monospace">VkSurfaceKHR</span> variable.
+It simply passes through the <span style="font-family: Courier New,Courier,monospace">VkResult</span> from the relevant platform call. </p>
+<pre class="prettyprint">
+SDL_Vulkan_CreateSurface(demo->sdl_window, (SDL_vulkanInstance)demo->inst, (SDL_vulkanSurface*)&demo->surface);
+</pre>
+</li></ol>
+</li>
+<li>Create the presentation queue.
+<p>Although the Vulkan implementation can support window system integration, that does not mean that every device in the system supports it. Therefore, you need to ensure that a device can present images to the surface you created. Since the presentation is a queue-specific feature, the problem is actually about finding a queue family that supports presenting to the surface you created.</p>
+
+<ol type="a">
+<li>Look for a queue family that has the capability of presenting to your window surface, by using the <span style="font-family: Courier New,Courier,monospace">vkGetPhysicalDeviceSurfaceSupportKHR()</span> function, which takes the physical device, queue family index, and surface as parameters. Then simply check the value of the <span style="font-family: Courier New,Courier,monospace">boolean</span> and store the presentation family queue index. Note that it is very likely that it ends up being the same queue family as previously selected for the physical device, so the example adds logic to explicitly prefer a physical device that supports drawing and presentation in the same queue for improved performance:
+<pre class="prettyprint">
+demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface, &supportsPresent[i]);
+demo->graphics_queue_node_index = graphicsQueueNodeIndex;
+</pre>
+</li>
+<li>Add a member variable for the <span style="font-family: Courier New,Courier,monospace">VkQueue</span> handle:
+<pre class="prettyprint">
+VkQueue queue;
+</pre></li>
+<li>Ideally, you need multiple <span style="font-family: Courier New,Courier,monospace">VkDeviceQueueCreateInfo</span> structs to create a queue from both graphics and presentation queue families. An elegant way to do that is to create a set of all unique queue families that are necessary for the required queues and modify <span style="font-family: Courier New,Courier,monospace">VkDeviceCreateInfo</span> to point to the vector. However, in this example, as the queue families are the same and the 2 handles most likely have the same value, you only need to pass the same index once and retrieve the queue handle:
+<pre class="prettyprint">
+vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0, &demo->queue);
+</pre>
+<p>Now the queue handle is ready.</p>
+</li></ol></li>
+<li>Prepare the rendering infrastructure.
+<p>You have successfully created the main handles to access the GPU to request rendering. Now prepare the rendering infrastructure, such as buffers, textures, vertices, render pass, descriptors, commands, and frame buffers, before initiating the actual drawing:</p>
+<pre class="prettyprint">
+static void
+demo_prepare(struct demo *demo)
+{
+ demo_prepare_buffers(demo);
+ demo_prepare_depth(demo);
+ demo_prepare_textures(demo);
+ demo_prepare_vertices(demo);
+ demo_prepare_descriptor_layout(demo);
+ demo_prepare_render_pass(demo);
+ demo_prepare_pipeline(demo);
+
+ demo_prepare_descriptor_pool(demo);
+ demo_prepare_descriptor_set(demo);
+
+ demo_prepare_framebuffers(demo);
+
+ demo->prepared = true;
+}
+</pre>
+</li>
+<li>Initiate rendering from the main loop.
+<p>Now you are set to perform continuous rendering from the application main loop. Initiate the main loop and call the rendering routine as well as start polling for user input events:</p>
+<pre class="prettyprint">
+while(1) {
+ while (SDL_PollEvent(&event)) {
+ printf("SDL Event type :: %d\n", event.type);
+ if (event.type == SDL_MOUSEBUTTONDOWN)
+ printf("SDL_MOUSEBUTTONDOWN Event!!\n");
+ if (event.type == SDL_MOUSEMOTION)
+ printf("SDL_MOUSEMOTION Event!!\n");
+ }
+ demo_run(&demo);
+}
+</pre>
+</li>
+<li>Before exiting the application, destroy all the Vulkan resources as well as the SDL window that needs to be explicitly freed up:
+<pre class="prettyprint">
+demo_cleanup(&demo);
+SDL_DestroyWindow(demo.sdl_window);
+
+SDL_Quit();
+</pre>
+</li>
+</ol>
+<h2 id="SDL_event">Handling General SDL Events</h2>
+
+<p>To handle general SDL events:</p>
+
+<ol>
+<li>Call the <span style="font-family: Courier New,Courier,monospace">SDL_PollEvent()</span> function, which polls the currently pending events and returns the <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> instance. Before calling the <span style="font-family: Courier New,Courier,monospace">SDL_PollEvent()</span> function, create an empty <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> structure.
+<pre class="prettyprint">
+void
+updateApp(appdata_s* ad)
+{
+ /* SDL_Event is a union that contains structures for the different event types */
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] Event type: %x\n", event.type);
+ handleEvent(&ad, &event);
+ }
+}
+</pre>
+</li>
+<li>The <span style="font-family: Courier New,Courier,monospace">SDL_PollEvent()</span> function removes the next event from the event queue. If there is no event in the queue, it returns 0. If there is an event, it fills the <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> object with the event information.
+<p>The <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> object is a union that contains structures for the different event types. The <span style="font-family: Courier New,Courier,monospace">type</span> member specifies the event type, shared with all events. The <span style="font-family: Courier New,Courier,monospace">type</span> member is related to the <a href="https://wiki.libsdl.org/SDL_EventType" target="blank">SDL_EventType</a> enumeration.</p>
+<p>To handle each event type separately, use a switch statement:</p>
+
+<pre class="prettyprint">
+void
+handleEvent(appdata_s** data, SDL_Event* event)
+{
+ appdata_s* ad = *data;
+
+ switch (event->type) {
+ case SDL_QUIT:
+ {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] Finish main loop ");
+ ad->game_exit = 1;
+ break;
+ }
+ case SDL_KEYUP:
+ {
+ char* scancodename = (char *)SDL_GetScancodeName(event->key.keysym.scancode);
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] keyboard scancode: %s", scancodename);
+ if (event->key.keysym.scancode == SDL_SCANCODE_AC_BACK) {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] Finish main loop ");
+ ad->game_exit = 1;
+ }
+ break;
+ }
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL]Mouse Down: %d x %d", event->button.x, event->button.y);
+ break;
+ }
+ case SDL_MOUSEBUTTONUP:
+ {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL]Mouse Up: %d x %d", event->button.x, event->button.y);
+ break;
+ }
+ case SDL_MOUSEMOTION:
+ {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL]Mouse Motion: %d x %d", event->motion.x, event->motion.y);
+ break;
+ }
+ case SDL_ROTATEEVENT:
+ {
+ ad->window_rotation = (int)event->user.data1;
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] Rotation degree: %d", ad->window_rotation);
+ break;
+ }
+ case SDL_WINDOWEVENT:
+ {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SDL_WINDOWEVENT Event!!");
+ if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
+ SDL_Log("SDL_WINDOWEVENT_SIZE_CHANGED!!!");
+ break;
+ }
+ } /* End switch */
+}
+</pre>
+</li>
+</ol>
+
+<h2 id="tizen_event">Handling Tizen-specific SDL Events</h2>
+
+<p>To handle SDl events specifically added to the Tizen application framework:</p>
+
+<ul>
+<li><span style="font-family: Courier New,Courier,monospace">SDL_APP_CONTROL</span>
+<p>This event is invoked when the application is launched with some parameters. In Tizen, this event is called in the <span style="font-family: Courier New,Courier,monospace">_tizen_sdl_control()</span> function.</p>
+
+<p>The application framework calls the application's application control callback just after the application enters the main loop. This callback is passed to the <span style="font-family: Courier New,Courier,monospace">app_control</span> instance containing the reason why the application was launched. For example, the application can be launched to open a file to handle the request that has been sent by another application. In any case, the application is responsible for checking the <span style="font-family: Courier New,Courier,monospace">app_control</span> content and responding appropriately. The <span style="font-family: Courier New,Courier,monospace">app_control</span> content can be empty, if the application is launched from the launcher.</p>
+<p>In SDL, <span style="font-family: Courier New,Courier,monospace">SDL_APP_CONTROL</span> has been defined as a new <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> event type for the application control. After the application enters the main loop, SDL sends the <span style="font-family: Courier New,Courier,monospace">SDL_APP_CONTROL</span> event to the application. This means that the application can confirm the <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> in the event loop. The event is defined as an <span style="font-family: Courier New,Courier,monospace">SDL_UserEvent</span>, which is in the <span style="font-family: Courier New,Courier,monospace">user</span> member of the <span style="font-family: Courier New,Courier,monospace">SDL_Event</span> union.</p>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">user</span> structure contains <span style="font-family: Courier New,Courier,monospace">data1</span> (<span style="font-family: Courier New,Courier,monospace">app_control</span>) and <span style="font-family: Courier New,Courier,monospace">data2</span> (<span style="font-family: Courier New,Courier,monospace">user_data</span>).</p>
+
+<p>In Tizen, you must include the <span style="font-family: Courier New,Courier,monospace"><app.h></span> header file to use the application control. For more information, see the <a href="../app_management/app_controls_n.htm">Application Controls</a> guide.</p>
+<pre class="prettyprint">
+#include <app.h>
+
+case SDL_APP_CONTROL:
+ app_control_h app_control = event.user.data1;
+ void *user_data = event.user.data2;
+
+ char *operation;
+ char *uri;
+
+ app_control_get_operation(app_control, &operation);
+ if (!strcmp(operation, APP_CONTROL_OPERATION_VIEW)) {
+ app_control_get_uri(app_control, &uri);
+ app_control_get_extra_data(app_control, "action", &action);
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Get path: [%s], action: [%s]", uri, action);
+ }
+break;
+</pre>
+</li>
+<li><span style="font-family: Courier New,Courier,monospace">SDL_APP_LOWBATTERY</span>
+<p>This event is invoked when the application is low on battery. Use it to reduce power consumption, if possible. In Tizen, this event is called in the <span style="font-family: Courier New,Courier,monospace">_tizen_app_low_battery()</span> function.</p>
+<p>Get the low battery status from the given event info by calling the <span style="font-family: Courier New,Courier,monospace">app_event_get_low_battery_status()</span> function. The <span style="font-family: Courier New,Courier,monospace">app_event_low_battery_status_e</span> is the enumeration for the battery status: <span style="font-family: Courier New,Courier,monospace">APP_EVENT_LOW_BATTERY_POWER_OFF</span> means that the battery charge is under 1% and <span style="font-family: Courier New,Courier,monospace">APP_EVENT_LOW_BATTERY_CRITICAL_LOW</span> under 5%.</p>
+
+<pre class="prettyprint">
+#include <app.h>
+
+case SDL_APP_LOWBATTERY:
+{
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] SDL_APP_LOWBATTERY ");
+
+ app_event_info_h event_info = event->user.data1;
+ void *user_data = event->user.data2;
+
+ app_event_low_battery_status_e status;
+ int ret = app_event_get_low_battery_status(event_info, &status);
+ if (ret == APP_ERROR_NONE) {
+ if (status == APP_EVENT_LOW_BATTERY_POWER_OFF)
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] The battery status is under 1% ");
+ else if (status == APP_EVENT_LOW_BATTERY_CRITICAL_LOW)
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] The battery status is under 5% ");
+ }
+ break;
+}
+</pre>
+</li>
+<li><span style="font-family: Courier New,Courier,monospace">SDL_APP_LANGUAGE_CHANGED</span>
+<p>This event is invoked when the displayed language is changed by the system. In Tizen, this event is called in the <span style="font-family: Courier New,Courier,monospace">_tizen_app_lang_changed()</span> function.</p>
+<p>Get the language from the given event info by calling the <span style="font-family: Courier New,Courier,monospace">app_event_get_language()</span> function.</p>
+<pre class="prettyprint">
+#include <app.h>
+
+case SDL_APP_LANGUAGE_CHANGED:
+{
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] SDL_APP_LANGUAGE_CHANGED ");
+
+ app_event_info_h event_info = event->user.data1;
+ void *user_data = event->user.data2;
+
+ char *language;
+ int ret = app_event_get_language(event_info, &language);
+ if (ret != APP_ERROR_NONE)
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] app_event_get_language failed. Err = %d ", ret);
+
+ if (language != NULL) {
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] language: ", language);
+ free(language);
+ }
+ break;
+}
+</pre>
+</li>
+<li><span style="font-family: Courier New,Courier,monospace">SDL_ROTATEEVENT</span>
+<p>This event is invoked when the device orientation changes. In Tizen, this event is called in the <span style="font-family: Courier New,Courier,monospace">_tizen_app_orient_changed()</span> function.</p>
+<p>Tizen supports portrait and landscape screen orientations, and you must take care of how your application responds to rotation changes. Use the <span style="font-family: Courier New,Courier,monospace">SDL_SetHint()</span> function to set the orientations with <span style="font-family: Courier New,Courier,monospace">SDL_HINT_ORIENTATIONS</span>. A hint specifies a variable controlling which orientations are allowed in Tizen.</p>
+
+<p align="center" class="Table"><strong>Table: Allowed orientations</strong></p>
+<table>
+<tbody>
+<tr>
+ <th>Orientation</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td><span style="font-family: Courier New,Courier,monospace">LandscapeLeft</span></td>
+ <td>Top of the device on the left</td>
+</tr>
+<tr>
+ <td><span style="font-family: Courier New,Courier,monospace">LandscapeRight</span></td>
+ <td>Top of the device on the right</td>
+</tr>
+<tr>
+ <td><span style="font-family: Courier New,Courier,monospace">Portrait</span></td>
+ <td>Top of device up</td>
+</tr>
+</tbody>
+</table>
+<pre class="prettyprint">
+SDL_SetHint(SDL_HINT_ORIENTATIONS, "Portrait LandscapeLeft LandscapeRight");
+
+case SDL_ROTATEEVENT:
+{
+ ad->window_rotation = (int)event->user.data1;
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[SDL] Rotation degree: %d", ad->window_rotation);
+ break;
+}
+</pre>
+</li>
+</ul>
+
+<script type="text/javascript" src="../../scripts/jquery.zclip.min.js"></script>
+<script type="text/javascript" src="../../scripts/showhide.js"></script>
+</div></div></div>
+
+<a class="top sms" href="#"><img src="../../images/btn_top.gif" alt="Go to top" /></a>
+
+<div id="footer">
+<p class="footer">Except as noted, this content - excluding the Code Examples - is licensed under <a href="http://creativecommons.org/licenses/by/3.0/legalcode" target="_blank">Creative Commons Attribution 3.0</a> and all of the Code Examples contained herein are licensed under <a href="https://www.tizen.org/bsd-3-clause-license" target="_blank">BSD-3-Clause</a>.<br/>For details, see the <a href="https://www.tizen.org/content-license" target="_blank">Content License</a>.</p>
+</div>
+
+<script type="text/javascript">
+var _gaq = _gaq || [];
+_gaq.push(['_setAccount', 'UA-25976949-1']);
+_gaq.push(['_trackPageview']);
+(function() {
+var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+})();
+</script>
+
+</body>
+</html>
+