2 * This is the test code that allows to run Vulkan backend
3 * as standalone application. Supports both Xcb and Xlib window
4 * integration. MUST NOT BE COMPILED WITH DALI!
7 // for surface implementation
8 #ifndef VK_USE_PLATFORM_XLIB_KHR
9 #define VK_USE_PLATFORM_XLIB_KHR
11 #ifndef VK_USE_PLATFORM_XCB_KHR
12 #define VK_USE_PLATFORM_XCB_KHR
15 #include <glm/glm.hpp>
16 #include <glm/matrix.hpp>
17 #include <glm/vector_relational.hpp>
18 #include <glm/gtc/matrix_transform.hpp>
22 #include <dali/integration-api/graphics/vulkan/vulkan-hpp-wrapper.h>
24 #include <dali/integration-api/graphics/vulkan/vk-surface-factory.h>
25 #include <dali/integration-api/graphics/graphics.h>
30 #include <dali/graphics/vulkan/vulkan-buffer.h>
31 #include <dali/graphics/vulkan/vulkan-graphics.h>
32 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
33 #include <dali/graphics/vulkan/vulkan-shader.h>
34 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
35 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
36 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h>
37 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
38 #include <dali/graphics/vulkan/vulkan-pipeline.h>
39 #include <dali/graphics/vulkan/vulkan-command-pool.h>
40 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
41 #include <dali/graphics/vulkan/vulkan-surface.h>
42 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
44 #include "generated/spv-shaders-gen.h"
49 using Dali::Integration::Graphics::Graphics;
50 using Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
51 using Dali::Graphics::Vulkan::Buffer;
52 using Dali::Graphics::Vulkan::DeviceMemory;
53 using Dali::Graphics::Vulkan::Shader;
54 using Dali::Graphics::Vulkan::DescriptorSetLayout;
55 using Dali::Graphics::Vulkan::GpuMemoryManager;
56 using Dali::Graphics::Vulkan::GpuMemoryAllocator;
57 using Dali::Graphics::Vulkan::Shader;
58 using Dali::Graphics::Vulkan::ShaderRef;
59 using Dali::Graphics::Vulkan::Pipeline;
60 using Dali::Graphics::Vulkan::PipelineRef;
61 using Dali::Graphics::Vulkan::CommandPool;
62 using Dali::Graphics::Vulkan::CommandBuffer;
63 using Dali::Graphics::Vulkan::DescriptorPool;
65 extern std::vector<uint8_t> VSH;
66 extern std::vector<uint8_t> FSH;
68 template< typename T, typename... Args >
69 std::unique_ptr< T > MakeUnique(Args&&... args)
71 return std::unique_ptr< T >(new T(std::forward< Args >(args)...));
75 class VkSurfaceXlib : public Dali::Integration::Graphics::Vulkan::VkSurfaceFactory
79 * Instantiates surface factory ( should
83 VkSurfaceXlib(Display* display, Window window)
84 : VkSurfaceFactory(), mDisplay(display), mWindow(window)
88 virtual vk::SurfaceKHR Create(vk::Instance instance, vk::AllocationCallbacks* allocCallbacks,
89 vk::PhysicalDevice physicalDevice) const override
91 vk::XlibSurfaceCreateInfoKHR info;
92 info.setDpy(mDisplay).setWindow(mWindow);
93 auto retval = instance.createXlibSurfaceKHR(info, allocCallbacks).value;
100 vk::SurfaceKHR mSurface;
103 class VkSurfaceXcb : public Dali::Integration::Graphics::Vulkan::VkSurfaceFactory
107 * Instantiates surface factory ( should
111 VkSurfaceXcb(xcb_connection_t* connection, xcb_window_t window)
112 : VkSurfaceFactory{}, mConnection(connection), mWindow(window)
116 virtual vk::SurfaceKHR Create(vk::Instance instance, vk::AllocationCallbacks* allocCallbacks,
117 vk::PhysicalDevice physicalDevice) const override
119 vk::XcbSurfaceCreateInfoKHR info;
120 info.setConnection(mConnection).setWindow(mWindow);
121 auto retval = instance.createXcbSurfaceKHR(info, allocCallbacks).value;
126 xcb_connection_t* mConnection;
127 xcb_window_t mWindow;
128 vk::SurfaceKHR mSurface;
138 Display* display{nullptr};
142 XDestroyWindow(display, window);
146 std::unique_ptr< xlib_window_t > create_xlib_window(int width, int height)
148 std::unique_ptr< xlib_window_t > wnd{new xlib_window_t};
149 // 1. Create Window ( done by DALI
152 wnd->height = height;
153 wnd->display = XOpenDisplay(nullptr);
154 auto defaultScreen = DefaultScreen(wnd->display);
156 XCreateSimpleWindow(wnd->display, RootWindow(wnd->display, defaultScreen), 0, 0, wnd->width,
157 wnd->height, 1, BlackPixel(wnd->display, defaultScreen),
158 WhitePixel(wnd->display, defaultScreen));
160 XSelectInput(wnd->display, wnd->window, ExposureMask | KeyPressMask);
161 XMapWindow(wnd->display, wnd->window);
162 XSync(wnd->display, false);
171 ::xcb_window_t window;
172 xcb_connection_t* connection;
176 xcb_destroy_window(connection, window);
180 std::unique_ptr< Test::xcb_window_t > create_xcb_window(int width, int height)
182 std::unique_ptr< Test::xcb_window_t > wnd{new Test::xcb_window_t};
183 // 1. Create Window ( done by DALI
186 wnd->height = height;
190 xcb_connection_t* connection = xcb_connect(NULL, &screenNum);
191 const xcb_setup_t* setup = xcb_get_setup(connection);
192 xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
193 for(int i = 0; i < screenNum; ++i)
194 xcb_screen_next(&iter);
196 xcb_screen_t* screen = iter.data;
197 ::xcb_window_t window = xcb_generate_id(connection);
199 uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
200 uint32_t values[] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS};
202 xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, wnd->width,
203 wnd->height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask,
206 xcb_map_window(connection, window);
207 const uint32_t coords[] = {100, 100};
208 xcb_configure_window(connection, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
209 xcb_flush(connection);
211 wnd->connection = connection;
212 wnd->window = window;
221 Dali::Graphics::Vulkan::GpuMemoryBlockHandle test_gpu_memory_manager( Dali::Graphics::Vulkan::Graphics& graphics,
222 GpuMemoryManager& gpuManager,
223 const Dali::Graphics::Vulkan::Handle<Buffer>& buffer )
225 auto device = graphics.GetDevice();
226 auto& allocator = graphics.GetAllocator();
228 auto& gpuAllocator = gpuManager.GetDefaultAllocator();
229 return gpuAllocator.Allocate( buffer, vk::MemoryPropertyFlagBits::eHostVisible );
238 } __attribute__((aligned(16)));
247 void update_buffer( Dali::Graphics::Vulkan::BufferHandle buffer, T& value )
249 auto ptr = reinterpret_cast<T*>(buffer->GetMemoryHandle()->Map());
251 buffer->GetMemoryHandle()->Unmap();
254 void update_translation( Dali::Graphics::Vulkan::BufferHandle buffer )
256 static float x = 0.0f;
260 ub.modelMat = mat4{1.0f};
261 ub.modelMat = glm::translate( ub.modelMat, vec3( x, x, 0.0f ));
262 ub.modelMat = glm::rotate( ub.modelMat, glm::radians( x ), glm::vec3( 0.0f, 0.0f, 1.0f) );
263 ub.viewMat = lookAt( vec3( 0.0f, 0.0f, 10.0f ),
264 vec3( 0.0f, 0.0f, 0.0f ),
265 vec3( 0.0f, 1.0f, 0.0f ) );
267 glm::mat4 clip( 1.0f, 0.0f, 0.0f, 0.0f,
268 0.0f, -1.0f, 0.0f, 0.0f,
269 0.0f, 0.0f, 0.5f, 0.0f,
270 0.0f, 0.0f, 0.5f, 1.0f );
272 ub.projMat = clip * ortho( 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 100.0f );
273 ub.color = vec4( x / 640.0f, x / 480.0f, 1.0f, 1.0f );
274 update_buffer( buffer, ub );
277 Dali::Graphics::Vulkan::BufferHandle create_uniform_buffer( Dali::Graphics::Vulkan::Graphics& gr )
279 // create uniform buffer
280 auto uniformBuffer = Buffer::New( gr, sizeof(UniformData), Buffer::Type::UNIFORM );
283 auto memory = gr.GetDeviceMemoryManager().GetDefaultAllocator().Allocate( uniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible );
286 uniformBuffer->BindMemory( memory );
288 auto ub = reinterpret_cast<UniformData*>(memory->Map());
290 ub->modelMat = mat4{1.0f};
291 //ub->modelMat = glm::translate( ub->modelMat, vec3( 0.0f, 0.0f, 0.0f ));
293 ub->viewMat = lookAt( vec3( 0.0f, 0.0f, 10.0f ),
294 vec3( 0.0f, 0.0f, 0.0f ),
295 vec3( 0.0f, 1.0f, 0.0f ) );
297 glm::mat4 clip( 1.0f, 0.0f, 0.0f, 0.0f,
298 0.0f, -1.0f, 0.0f, 0.0f,
299 0.0f, 0.0f, 0.5f, 0.0f,
300 0.0f, 0.0f, 0.5f, 1.0f );
302 ub->projMat = clip * ortho( 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 100.0f );
303 ub->color = vec4( 0.0f, 1.0f, 1.0f, 1.0f );
306 MVP = ub->projMat * ub->viewMat * ub->modelMat;
310 return uniformBuffer;
313 Dali::Graphics::Vulkan::Handle<DescriptorPool>
314 create_descriptor_pool( Dali::Graphics::Vulkan::Graphics& gr )
316 vk::DescriptorPoolSize size;
317 size.setDescriptorCount( 1024 ).setType( vk::DescriptorType::eUniformBuffer );
319 // TODO: how to organize this???
320 auto pool = DescriptorPool::New( gr,
321 vk::DescriptorPoolCreateInfo{}.
323 setPoolSizeCount(1).setPPoolSizes(&size));
330 using namespace Dali::Graphics::Vulkan;
331 GpuMemoryBlockHandle handle( new GpuMemoryBlock() );
333 decltype(handle) handle2 = handle;
334 handle.GetRefCount();*/
338 create_pipeline( Dali::Graphics::Vulkan::Graphics& graphics,
339 Dali::Graphics::Vulkan::ShaderRef vertexShader,
340 Dali::Graphics::Vulkan::ShaderRef fragmentShader
343 using namespace Dali::Graphics::Vulkan;
344 auto pipelineInfo = vk::GraphicsPipelineCreateInfo{};
345 auto pipeline = Pipeline::New( graphics, pipelineInfo );
347 pipeline->SetShader( vertexShader, Shader::Type::VERTEX );
348 pipeline->SetShader( fragmentShader, Shader::Type::FRAGMENT );
349 pipeline->SetViewport( 0, 0, 640, 480 );
350 pipeline->SetVertexInputState(
351 std::vector<vk::VertexInputAttributeDescription>{vk::VertexInputAttributeDescription{}.
355 setFormat( vk::Format::eR32G32B32Sfloat )},
356 std::vector<vk::VertexInputBindingDescription>{vk::VertexInputBindingDescription{}.
358 setStride( sizeof(float)*3 ).
359 setInputRate( vk::VertexInputRate::eVertex)}
361 pipeline->SetInputAssemblyState( vk::PrimitiveTopology::eTriangleList, false );
363 if( !pipeline->Compile() )
374 auto window = Test::create_xlib_window(640, 480);
375 auto surfaceFactory =
376 std::unique_ptr< VkSurfaceXlib >{new VkSurfaceXlib{window->display, window->window}};
378 auto window = Test::create_xcb_window(640, 480);
379 auto surfaceFactory =
380 std::unique_ptr<VkSurfaceXcb>{new VkSurfaceXcb{window->connection, window->window}};
384 auto graphics = MakeUnique<Graphics>();
385 auto fbid = graphics->Create( std::move(surfaceFactory) );
387 // access internal implementation
388 auto& gr = graphics->GetImplementation<Dali::Graphics::Vulkan::Graphics>();
390 // GPU memory manager
391 auto& memmgr = gr.GetDeviceMemoryManager();
393 const vec3 VERTICES[] =
396 {320.0f, 0.0f, 0.0f},
397 {0.0f, 160.0f, 0.0f},
404 auto vertexShader = Shader::New( gr, VSH_CODE.data(), VSH_CODE.size() );
405 vertexShader->SetDescriptorSetLayout( 0, vk::DescriptorSetLayoutCreateInfo{}.
406 setBindingCount( 1 ).
407 setPBindings( std::vector<vk::DescriptorSetLayoutBinding>{
408 vk::DescriptorSetLayoutBinding{}.
410 setStageFlags( vk::ShaderStageFlagBits::eVertex ).
411 setDescriptorType( vk::DescriptorType::eUniformBuffer ).
412 setDescriptorCount( 1 )
416 auto fragmentShader = Shader::New( gr, FSH_CODE.data(), FSH_CODE.size() );
419 auto vertexBuffer = Buffer::New( gr, sizeof(float)*3*3, Buffer::Type::VERTEX );
421 auto descriptorPool = create_descriptor_pool( gr );
422 auto descriptorSet = descriptorPool->AllocateDescriptorSets( vk::DescriptorSetAllocateInfo{}
423 .setPSetLayouts( vertexShader->GetDescriptorSetLayouts().data() )
424 .setDescriptorSetCount( static_cast<uint32_t>(vertexShader->GetDescriptorSetLayouts().size())));
428 auto& gpuManager = gr.GetDeviceMemoryManager();
430 auto bufferMemory = test_gpu_memory_manager( gr, gpuManager, vertexBuffer );
431 vertexBuffer->BindMemory( bufferMemory );
433 auto ptr = static_cast<uint8_t*>(bufferMemory->Map());
434 std::copy( reinterpret_cast<const uint8_t*>(VERTICES), reinterpret_cast<const uint8_t*>(VERTICES)+(sizeof(float)*9), ptr);
435 bufferMemory->Unmap();
437 auto pipeline = create_pipeline( gr, vertexShader, fragmentShader );
439 auto commandPool = CommandPool::New( gr );
441 auto uniformBuffer = create_uniform_buffer( gr );
443 descriptorSet[0]->WriteUniformBuffer( 0, uniformBuffer, 0, uniformBuffer->GetSize() );
446 auto cmdDraw = commandPool->NewCommandBuffer( false );
449 cmdDraw->Begin( vk::CommandBufferUsageFlagBits::eRenderPassContinue);
452 cmdDraw->BindVertexBuffer( 0, vertexBuffer, 0 );
455 cmdDraw->BindGraphicsPipeline( pipeline );
458 cmdDraw->BindDescriptorSets( descriptorSet, 0 );
461 cmdDraw->Draw( 3, 1, 0, 0 );
472 graphics->PreRender( fbid );
475 auto cmdbuf = gr.GetSurface( fbid ).GetCurrentCommandBuffer();
477 // get command buffer for current frame and execute the draw call
478 cmdbuf->ExecuteCommands( { cmdDraw } );
481 graphics->PostRender( fbid );
483 update_translation( uniformBuffer );
491 VulkanTest::RunTestMain();