[Vulkan] Image and Swapchain upgrade
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-graphics-controller.cpp
1 #include "generated/spv-shaders-gen.h"
2
3 #include <glm/glm.hpp>
4 #include <glm/gtc/matrix_transform.hpp>
5 #include <glm/matrix.hpp>
6 #include <glm/vector_relational.hpp>
7
8 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h>
9 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
10 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
11 #include <dali/graphics/vulkan/vulkan-buffer.h>
12 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
13 #include <dali/graphics/vulkan/vulkan-command-pool.h>
14 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
15 #include <dali/graphics/vulkan/vulkan-graphics-controller.h>
16 #include <dali/graphics/vulkan/vulkan-graphics.h>
17 #include <dali/graphics/vulkan/vulkan-pipeline.h>
18 #include <dali/graphics/vulkan/vulkan-shader.h>
19 #include <dali/graphics/vulkan/vulkan-framebuffer.h>
20 #include <dali/graphics/vulkan/vulkan-surface.h>
21
22 using namespace glm;
23
24 namespace Dali
25 {
26 namespace Graphics
27 {
28 namespace Vulkan
29 {
30 static const mat4 CLIP_MATRIX(
31   1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f );
32
33 struct Controller::Impl
34 {
35   struct State
36   {
37     ShaderRef                     vertexShader;
38     ShaderRef                     fragmentShader;
39     DescriptorPoolRef             descriptorPool;
40     PipelineRef                   pipeline;
41     BufferRef                     vertexBuffer;
42     BufferRef                     uniformBuffer0;
43     BufferRef                     uniformBuffer1; // clip matrix
44     std::vector<DescriptorSetRef> descriptorSets;
45     CommandPoolRef                commandPool;
46     CommandBufferRef              drawCommand;
47
48     std::vector<CommandBufferRef> drawCommandPool; // max 1024 secondary buffers
49     uint32_t                      drawPoolIndex{0u};
50   };
51
52   Impl( Controller& owner, Dali::Graphics::Vulkan::Graphics& graphics )
53   : mGraphics( graphics ),
54     mOwner( owner ),
55     mDefaultAllocator( mGraphics.GetDeviceMemoryManager().GetDefaultAllocator() )
56   {
57   }
58
59   ~Impl()
60   {
61   }
62
63   // TODO: @todo this function initialises basic buffers, shaders and pipeline
64   // for the prototype ONLY
65 #pragma GCC diagnostic push
66 #pragma GCC diagnostic ignored "-Wframe-larger-than="
67   bool Initialise()
68   {
69     mDebugPipelineState.vertexShader = Shader::New( mGraphics, VSH_CODE.data(), VSH_CODE.size() );
70
71     mDebugPipelineState.fragmentShader = Shader::New( mGraphics, FSH_CODE.data(), FSH_CODE.size() );
72
73     mDebugPipelineState.descriptorPool = CreateDescriptorPool();
74
75     const float halfWidth  = 0.5f;
76     const float halfHeight = 0.5f;
77     //#if 0
78     const vec3 VERTICES[4] = {
79       {halfWidth, halfHeight, 0.0f},
80       {halfWidth, -halfHeight, 0.0f},
81       {-halfWidth, halfHeight, 0.0f},
82       {-halfWidth, -halfHeight, 0.0f},
83     };
84 //#endif
85 #if 0
86     const vec3 VERTICES[4] = {
87       {-halfWidth, -halfHeight, 0.0f},
88       {halfWidth,  -halfHeight, 0.0f},
89       {halfWidth,  halfHeight, 0.0f},
90       {-halfWidth, halfHeight, 0.0f}
91     };
92 #endif
93     mDebugPipelineState.vertexBuffer = Buffer::New( mGraphics, sizeof( VERTICES[0] ) * 4, Buffer::Type::VERTEX );
94     auto& defaultAllocator           = mGraphics.GetDeviceMemoryManager().GetDefaultAllocator();
95     mDebugPipelineState.vertexBuffer->BindMemory(
96       defaultAllocator.Allocate( mDebugPipelineState.vertexBuffer, vk::MemoryPropertyFlagBits::eHostVisible ) );
97
98     auto ptr = mDebugPipelineState.vertexBuffer->GetMemoryHandle()->MapTyped<vec3>();
99     std::copy( VERTICES, VERTICES + 4, ptr );
100     mDebugPipelineState.vertexBuffer->GetMemoryHandle()->Unmap();
101
102     // create command pool
103     mDebugPipelineState.commandPool = CommandPool::New( mGraphics );
104
105     CreatePipeline( mDebugPipelineState );
106
107     // allocated descriptor pool ( 1024 sets, 1024 uniform buffers )
108     auto size = vk::DescriptorPoolSize{}.setDescriptorCount( 1024 ).setType( vk::DescriptorType::eUniformBuffer );
109     mDebugPipelineState.descriptorPool = DescriptorPool::New(
110       mGraphics, vk::DescriptorPoolCreateInfo{}.setPoolSizeCount( 1 ).setPPoolSizes( &size ).setMaxSets( 1024 ) );
111
112     mDebugPipelineState.uniformBuffer1 = Buffer::New( mGraphics, sizeof( CLIP_MATRIX ), Buffer::Type::UNIFORM );
113     mDebugPipelineState.uniformBuffer1->BindMemory(
114       mDefaultAllocator.Allocate( mDebugPipelineState.uniformBuffer1, vk::MemoryPropertyFlagBits::eHostVisible ) );
115
116     auto clipPtr = mDebugPipelineState.uniformBuffer1->GetMemoryHandle()->MapTyped<mat4>();
117     std::copy( &CLIP_MATRIX, &CLIP_MATRIX + 1, clipPtr );
118     mDebugPipelineState.uniformBuffer1->GetMemoryHandle()->Unmap();
119
120     return true;
121   }
122
123   PipelineRef CreatePipeline( State& state )
124   {
125     auto pipeline = Pipeline::New( mGraphics );
126
127     pipeline->SetShader( state.vertexShader, Shader::Type::VERTEX );
128     pipeline->SetShader( state.fragmentShader, Shader::Type::FRAGMENT );
129
130     auto size = mGraphics.GetSurface( 0u )->GetSize();
131     pipeline->SetViewport( 0, 0, static_cast<float>( size.width ), static_cast<float>( size.height ) );
132
133     pipeline->SetVertexInputState(
134       std::vector<vk::VertexInputAttributeDescription>{
135         vk::VertexInputAttributeDescription{}.setBinding( 0 ).setOffset( 0 ).setLocation( 0 ).setFormat(
136           vk::Format::eR32G32B32Sfloat )},
137       std::vector<vk::VertexInputBindingDescription>{vk::VertexInputBindingDescription{}
138                                                        .setBinding( 0 )
139                                                        .setStride( sizeof( vec3 ) )
140                                                        .setInputRate( vk::VertexInputRate::eVertex )} );
141     pipeline->SetInputAssemblyState( vk::PrimitiveTopology::eTriangleStrip, false );
142
143     if( !pipeline->Compile() )
144     {
145       pipeline.Reset();
146     }
147
148     state.pipeline = pipeline;
149     return pipeline;
150   }
151
152   void SubmitCommand( API::RenderCommand&& command )
153   {
154     auto& state = mDebugPipelineState;
155
156     const auto& bufferList = command.GetBufferList();
157     auto        drawcalls  = command.GetPrimitiveCount();
158
159     // create pool of commands to be re-recorded
160     if( state.drawCommandPool.empty() )
161     {
162       for( auto i = 0u; i < 1024; ++i )
163       {
164         state.drawCommandPool.push_back( state.commandPool->NewCommandBuffer( false ) );
165       }
166     }
167
168     uint32_t                      stride = sizeof( mat4 ) + sizeof( vec4 ) + sizeof( vec3 );
169     std::vector<CommandBufferRef> executeCommands;
170     for( auto&& buf : bufferList.Get() )
171     {
172       // TODO: @todo implement minimum offset!
173       const uint32_t sizeOfUniformBuffer      = U32( ( buf->GetSize() / drawcalls.Get() ) );
174       const uint32_t uniformBlockOffsetStride = ( ( sizeOfUniformBuffer / 256 ) + 1 ) * 256;
175       const uint32_t uniformBlockMemoryNeeded = U32( uniformBlockOffsetStride * drawcalls.Get() );
176
177       // create buffer if doesn't exist
178       if( !state.uniformBuffer0 )
179       {
180         state.uniformBuffer0 = Buffer::New( mGraphics, uniformBlockMemoryNeeded, Buffer::Type::UNIFORM );
181       }
182       if( state.uniformBuffer0->GetSize() < uniformBlockMemoryNeeded || !state.uniformBuffer0->GetMemoryHandle() )
183       {
184         // allocate and bind memory if needed ( buffer increased size or buffer hasn't been bound yet )
185         state.uniformBuffer0->BindMemory(
186           mDefaultAllocator.Allocate( state.uniformBuffer0, vk::MemoryPropertyFlagBits::eHostVisible ) );
187       }
188
189       // fill memory
190
191       struct UB
192       {
193         mat4 mvp;
194         vec4 color;
195         vec3 size;
196       } __attribute__( ( aligned( 16 ) ) );
197
198       auto memory = state.uniformBuffer0->GetMemoryHandle();
199       auto outPtr = memory->MapTyped<char>();
200       for( auto i = 0u; i < drawcalls.Get(); ++i )
201       {
202         // copy chunk of data
203         UB* inputData  = ( reinterpret_cast<UB*>( buf->GetDataBase() ) ) + i;
204         UB* outputData = ( reinterpret_cast<UB*>( outPtr + ( i * uniformBlockOffsetStride ) ) );
205         *outputData    = *inputData;
206
207         auto descriptorSets = state.descriptorPool->AllocateDescriptorSets(
208           vk::DescriptorSetAllocateInfo{}.setDescriptorSetCount( 1 ).setPSetLayouts(
209             state.pipeline->GetVkDescriptorSetLayouts().data() ) );
210
211         descriptorSets[0]->WriteUniformBuffer( 0, state.uniformBuffer0, i * uniformBlockOffsetStride, stride );
212         descriptorSets[0]->WriteUniformBuffer( 1, state.uniformBuffer1, 0, state.uniformBuffer1->GetSize() );
213
214         // record draw call
215         auto cmdbuf = state.commandPool->NewCommandBuffer( false );
216         cmdbuf->Begin( vk::CommandBufferUsageFlagBits::eRenderPassContinue );
217         cmdbuf->BindVertexBuffer( 0, state.vertexBuffer, 0 );
218         cmdbuf->BindGraphicsPipeline( state.pipeline );
219         cmdbuf->BindDescriptorSets( descriptorSets, 0 );
220         cmdbuf->Draw( 4, 1, 0, 0 );
221         cmdbuf->End();
222
223         executeCommands.push_back( cmdbuf );
224       }
225
226       memory->Unmap();
227
228       // execute buffer
229       mGraphics.GetSwapchainForFBID( 0u )->GetPrimaryCommandBuffer()->ExecuteCommands( executeCommands );
230
231       // break, one pass only
232       break;
233     }
234   }
235 #pragma GCC diagnostic pop
236   void BeginFrame()
237   {
238     auto surface = mGraphics.GetSurface( 0u );
239
240     auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
241     swapchain->AcquireNextFramebuffer();
242
243     // rewind pools
244     mDebugPipelineState.drawPoolIndex = 0u;
245     mDebugPipelineState.descriptorPool->Reset();
246     mDebugPipelineState.commandPool->Reset( true );
247   }
248
249   void EndFrame()
250   {
251     auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
252     swapchain->Present();
253   }
254
255   DescriptorPoolRef CreateDescriptorPool()
256   {
257     vk::DescriptorPoolSize size;
258     size.setDescriptorCount( 1024 ).setType( vk::DescriptorType::eUniformBuffer );
259
260     // TODO: how to organize this???
261     auto pool = DescriptorPool::New(
262       mGraphics, vk::DescriptorPoolCreateInfo{}.setMaxSets( 1024 ).setPoolSizeCount( 1 ).setPPoolSizes( &size ) );
263     return pool;
264   }
265
266   Graphics&           mGraphics;
267   Controller&         mOwner;
268   GpuMemoryAllocator& mDefaultAllocator;
269
270   State mDebugPipelineState;
271 };
272
273 // TODO: @todo temporarily ignore missing return type, will be fixed later
274 #pragma GCC diagnostic push
275 #pragma GCC diagnostic     ignored "-Wreturn-type"
276 API::Accessor<API::Shader> Controller::CreateShader( const API::BaseFactory<API::Shader>& factory )
277 {
278 }
279
280 API::Accessor<API::Texture> Controller::CreateTexture( const API::BaseFactory<API::Texture>& factory )
281 {
282 }
283
284 API::Accessor<API::TextureSet> Controller::CreateTextureSet( const API::BaseFactory<API::TextureSet>& factory )
285 {
286 }
287
288 API::Accessor<API::DynamicBuffer> Controller::CreateDynamicBuffer( const API::BaseFactory<API::DynamicBuffer>& factory )
289 {
290 }
291
292 API::Accessor<API::StaticBuffer> Controller::CreateStaticBuffer( const API::BaseFactory<API::StaticBuffer>& factory )
293 {
294 }
295
296 API::Accessor<API::Sampler> Controller::CreateSampler( const API::BaseFactory<API::Sampler>& factory )
297 {
298 }
299
300 API::Accessor<API::Framebuffer> Controller::CreateFramebuffer( const API::BaseFactory<API::Framebuffer>& factory )
301 {
302 }
303
304 std::unique_ptr<char> Controller::CreateBuffer( size_t numberOfElements, size_t elementSize )
305 {
306   return std::unique_ptr<char>( new char[numberOfElements * elementSize] );
307 }
308
309 #pragma GCC diagnostic pop
310
311 std::unique_ptr<Controller> Controller::New( Graphics& vulkanGraphics )
312 {
313   return std::make_unique<Controller>( vulkanGraphics );
314 }
315
316 Controller::Controller( Graphics& vulkanGraphics ) : mImpl( std::make_unique<Impl>( *this, vulkanGraphics ) )
317 {
318   mImpl->Initialise();
319 }
320
321 Controller::~Controller()       = default;
322 Controller::Controller()        = default;
323 Controller& Controller::operator=( Controller&& ) = default;
324
325 void Controller::GetRenderItemList()
326 {
327 }
328
329 void Controller::SubmitCommand( API::RenderCommand&& command )
330 {
331   mImpl->SubmitCommand( std::move( command ) );
332 }
333
334 void Controller::BeginFrame()
335 {
336   mImpl->BeginFrame();
337 }
338
339 void Controller::EndFrame()
340 {
341   mImpl->EndFrame();
342 }
343
344 } // namespace Vulkan
345 } // namespace Graphics
346 } // namespace Dali