8f715e6f31367acaad187bf8a064f2c163d24471
[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-surface.h>
20
21 using namespace glm;
22
23 namespace Dali
24 {
25 namespace Graphics
26 {
27 namespace Vulkan
28 {
29 static const mat4 CLIP_MATRIX(
30   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 );
31
32 struct Controller::Impl
33 {
34   struct State
35   {
36     ShaderRef                     vertexShader;
37     ShaderRef                     fragmentShader;
38     DescriptorPoolRef             descriptorPool;
39     PipelineRef                   pipeline;
40     BufferRef                     vertexBuffer;
41     BufferRef                     uniformBuffer0;
42     BufferRef                     uniformBuffer1; // clip matrix
43     std::vector<DescriptorSetRef> descriptorSets;
44     CommandPoolRef                commandPool;
45     CommandBufferRef              drawCommand;
46
47     std::vector<CommandBufferRef> drawCommandPool; // max 1024 secondary buffers
48     uint32_t                      drawPoolIndex{0u};
49   };
50
51   Impl( Controller& owner, Dali::Graphics::Vulkan::Graphics& graphics )
52   : mGraphics( graphics ),
53     mOwner( owner ),
54     mDefaultAllocator( mGraphics.GetDeviceMemoryManager().GetDefaultAllocator() )
55   {
56   }
57
58   ~Impl()
59   {
60   }
61
62   // TODO: @todo this function initialises basic buffers, shaders and pipeline
63   // for the prototype ONLY
64 #pragma GCC diagnostic push
65 #pragma GCC diagnostic ignored "-Wframe-larger-than="
66   bool Initialise()
67   {
68     mDebugPipelineState.vertexShader = Shader::New( mGraphics, VSH_CODE.data(), VSH_CODE.size() );
69
70     mDebugPipelineState.fragmentShader = Shader::New( mGraphics, FSH_CODE.data(), FSH_CODE.size() );
71
72     mDebugPipelineState.descriptorPool = CreateDescriptorPool();
73
74     const float halfWidth = 0.5f;
75     const float halfHeight = 0.5f;
76 //#if 0
77     const vec3 VERTICES[4] =
78                   {
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.GetSurface( 0u ).GetCurrentCommandBuffer()->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     surface.AcquireNextImage();
240
241     // rewind pools
242     mDebugPipelineState.drawPoolIndex = 0u;
243     mDebugPipelineState.descriptorPool->Reset();
244     mDebugPipelineState.commandPool->Reset( true );
245   }
246
247   void EndFrame()
248   {
249     auto& surface = mGraphics.GetSurface( 0u );
250     surface.Present();
251   }
252
253   DescriptorPoolRef CreateDescriptorPool()
254   {
255     vk::DescriptorPoolSize size;
256     size.setDescriptorCount( 1024 ).setType( vk::DescriptorType::eUniformBuffer );
257
258     // TODO: how to organize this???
259     auto pool = DescriptorPool::New(
260       mGraphics, vk::DescriptorPoolCreateInfo{}.setMaxSets( 1024 ).setPoolSizeCount( 1 ).setPPoolSizes( &size ) );
261     return pool;
262   }
263
264   Graphics&           mGraphics;
265   Controller&         mOwner;
266   GpuMemoryAllocator& mDefaultAllocator;
267
268   State mDebugPipelineState;
269 };
270
271 // TODO: @todo temporarily ignore missing return type, will be fixed later
272 #pragma GCC diagnostic push
273 #pragma GCC diagnostic     ignored "-Wreturn-type"
274 API::Accessor<API::Shader> Controller::CreateShader( const API::BaseFactory<API::Shader>& factory )
275 {
276 }
277
278 API::Accessor<API::Texture> Controller::CreateTexture( const API::BaseFactory<API::Texture>& factory )
279 {
280 }
281
282 API::Accessor<API::TextureSet> Controller::CreateTextureSet( const API::BaseFactory<API::TextureSet>& factory )
283 {
284 }
285
286 API::Accessor<API::DynamicBuffer> Controller::CreateDynamicBuffer( const API::BaseFactory<API::DynamicBuffer>& factory )
287 {
288 }
289
290 API::Accessor<API::StaticBuffer> Controller::CreateStaticBuffer( const API::BaseFactory<API::StaticBuffer>& factory )
291 {
292 }
293
294 API::Accessor<API::Sampler> Controller::CreateSampler( const API::BaseFactory<API::Sampler>& factory )
295 {
296 }
297
298 API::Accessor<API::Framebuffer> Controller::CreateFramebuffer( const API::BaseFactory<API::Framebuffer>& factory )
299 {
300 }
301
302 std::unique_ptr<char> Controller::CreateBuffer( size_t numberOfElements, size_t elementSize )
303 {
304   return std::unique_ptr<char>( new char[numberOfElements * elementSize] );
305 }
306
307 #pragma GCC diagnostic pop
308
309 std::unique_ptr<Controller> Controller::New( Graphics& vulkanGraphics )
310 {
311   return std::make_unique<Controller>( vulkanGraphics );
312 }
313
314 Controller::Controller( Graphics& vulkanGraphics ) : mImpl( std::make_unique<Impl>( *this, vulkanGraphics ) )
315 {
316   mImpl->Initialise();
317 }
318
319 Controller::~Controller()       = default;
320 Controller::Controller()        = default;
321 Controller& Controller::operator=( Controller&& ) = default;
322
323 void Controller::GetRenderItemList()
324 {
325 }
326
327 void Controller::SubmitCommand( API::RenderCommand&& command )
328 {
329   mImpl->SubmitCommand( std::move( command ) );
330 }
331
332 void Controller::BeginFrame()
333 {
334   mImpl->BeginFrame();
335 }
336
337 void Controller::EndFrame()
338 {
339   mImpl->EndFrame();
340 }
341
342 } // namespace Vulkan
343 } // namespace Graphics
344 } // namespace Dali