[Vulkan] Image and Swapchain upgrade
authoradam.b <jsr184@gmail.com>
Wed, 21 Mar 2018 12:05:56 +0000 (12:05 +0000)
committerFrancisco Santos <eggzcape@gmail.com>
Thu, 29 Mar 2018 16:36:49 +0000 (12:36 -0400)
Sync issues seem to be quite severe hence the new Swapchain object
is introduced which will make use of new Image, ImageView and Framebuffer wrappers.

- Swapchain and surface have been decoupled.
- Swapchain can be obtained now from FBID value
- Swapping buffers and presenting is responsibility of swapchain not surface
- Framebuffer object is responsible for storing own compatible render pass
- ImageView can be given external untracked vk::Image as a source
- New synchronisation mechanism in place ( brute force, but more stable )
- Fixed image layout transition

This patch requires SPIR-V parser.

Change-Id: I6cb64283109b648752ff341fe7fe165dc9bad5cb

30 files changed:
dali/graphics/file.list
dali/graphics/vulkan/generated/spv-shaders-gen.cpp
dali/graphics/vulkan/generated/spv-shaders-gen.h
dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h
dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.cpp
dali/graphics/vulkan/tests/texture-test.cpp [new file with mode: 0644]
dali/graphics/vulkan/vulkan-buffer.cpp
dali/graphics/vulkan/vulkan-buffer.h
dali/graphics/vulkan/vulkan-command-buffer.cpp
dali/graphics/vulkan/vulkan-command-buffer.h
dali/graphics/vulkan/vulkan-command-pool.cpp
dali/graphics/vulkan/vulkan-command-pool.h
dali/graphics/vulkan/vulkan-framebuffer.cpp
dali/graphics/vulkan/vulkan-framebuffer.h
dali/graphics/vulkan/vulkan-graphics-controller.cpp
dali/graphics/vulkan/vulkan-graphics.cpp
dali/graphics/vulkan/vulkan-graphics.h
dali/graphics/vulkan/vulkan-image.cpp
dali/graphics/vulkan/vulkan-image.h
dali/graphics/vulkan/vulkan-pipeline.cpp
dali/graphics/vulkan/vulkan-queue.cpp
dali/graphics/vulkan/vulkan-standalone-test.cpp
dali/graphics/vulkan/vulkan-surface.cpp
dali/graphics/vulkan/vulkan-surface.h
dali/graphics/vulkan/vulkan-swapchain.cpp [new file with mode: 0644]
dali/graphics/vulkan/vulkan-swapchain.h [new file with mode: 0644]
dali/graphics/vulkan/vulkan-types.h
dali/integration-api/graphics/graphics.cpp
dali/integration-api/graphics/graphics.h
dali/integration-api/graphics/surface-factory.h

index 6ec3e20..f4a0c43 100644 (file)
@@ -16,6 +16,7 @@ graphics_src_files = \
     $(graphics_src_dir)/vulkan/vulkan-buffer.cpp \
     $(graphics_src_dir)/vulkan/vulkan-graphics.cpp \
     $(graphics_src_dir)/vulkan/vulkan-shader.cpp \
+    $(graphics_src_dir)/vulkan/vulkan-swapchain.cpp \
     $(graphics_src_dir)/vulkan/vulkan-graphics-controller.cpp \
     $(graphics_src_dir)/vulkan/spirv/vulkan-spirv.cpp \
     $(graphics_src_dir)/graphics-controller.cpp
index a6b8988..7cb07c3 100644 (file)
@@ -140,7 +140,7 @@ std::vector<uint8_t> VSH_CODE = {
 };
 std::vector<uint8_t> FSH_CODE = {
   0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
-  0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
+  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
   0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
   0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -153,43 +153,23 @@ std::vector<uint8_t> FSH_CODE = {
   0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x43,
   0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
   0x0b, 0x00, 0x00, 0x00, 0x74, 0x72, 0x69, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
-  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x75, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x00, 0x00,
-  0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
   0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
-  0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00,
-  0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,
-  0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00,
-  0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x2c, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
-  0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-  0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
-  0x16, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
-  0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+  0x0b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
   0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
 };
 #pragma GCC diagnostic pop
index 5a4709f..7297c75 100644 (file)
@@ -39,11 +39,9 @@ extern std::vector<uint8_t> FSH_CODE;
 layout( location = 0 ) in vec4 triColor;
 layout( location = 0 ) out vec4 outColor;
 
-layout( binding = 2 ) uniform sampler2D uTexture;
-
 void main()
 {
-    outColor = triColor + texture( uTexture, vec2(0.5, 0.5));
+    outColor = triColor;
 }*/
 
 
index 5d5cd1e..26dabe3 100644 (file)
@@ -66,7 +66,7 @@ public:
    * @param memoryProperties
    * @return
    */
-  virtual GpuMemoryBlockRef Allocate( Image& buffer, vk::MemoryPropertyFlags memoryProperties ) = 0;
+  virtual GpuMemoryBlockRef Allocate( const ImageRef& buffer, vk::MemoryPropertyFlags memoryProperties ) = 0;
 
   // refcounting managed via allocator which ownes all the blocks, allocator may
   // implement this feature any way ( or simply ignore it )
index b979b56..da8a30c 100644 (file)
@@ -127,9 +127,9 @@ struct GpuMemoryDefaultAllocator : public GpuMemoryAllocator
    * @param memoryProperties
    * @return
    */
-  GpuMemoryBlockRef Allocate( Image& image, vk::MemoryPropertyFlags memoryProperties ) override
+  GpuMemoryBlockRef Allocate( const ImageRef& image, vk::MemoryPropertyFlags memoryProperties ) override
   {
-    return Allocate( mGraphics.GetDevice().getImageMemoryRequirements( image.GetVkImage() ),
+    return Allocate( mGraphics.GetDevice().getImageMemoryRequirements( image->GetVkImage() ),
                                memoryProperties );
   }
 
diff --git a/dali/graphics/vulkan/tests/texture-test.cpp b/dali/graphics/vulkan/tests/texture-test.cpp
new file mode 100644 (file)
index 0000000..b7152a3
--- /dev/null
@@ -0,0 +1,211 @@
+#include <string>
+#include <vector>
+#include <vulkan/vulkan.hpp>
+
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h>
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
+#include <dali/graphics/vulkan/vulkan-buffer.h>
+#include <dali/graphics/vulkan/vulkan-command-buffer.h>
+#include <dali/graphics/vulkan/vulkan-command-pool.h>
+#include <dali/graphics/vulkan/vulkan-graphics.h>
+#include <dali/graphics/vulkan/vulkan-image.h>
+#include <dali/graphics/vulkan/vulkan-fence.h>
+#include <dali/graphics/vulkan/vulkan-queue.h>
+
+
+namespace VulkanTest
+{
+using namespace Dali::Graphics::Vulkan;
+
+struct Pixel
+{
+  Pixel() = default;
+
+  explicit Pixel( uint32_t _color )
+    : color(_color)
+  {}
+
+  explicit Pixel( uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a)
+  {
+    r = _r;
+    g = _g;
+    b = _b;
+    a = _a;
+  }
+
+  union
+  {
+    uint32_t color;
+    struct
+    {
+      uint8_t r, g, b, a;
+    };
+  };
+};
+
+struct Pixmap
+{
+  explicit Pixmap( std::vector<Pixel> _data, uint32_t _width, uint32_t _height ) :
+  data(_data), width(_width), height(_height), bytesPerPixel(4), pixelFormat( vk::Format::eR32G32B32A32Uint )
+  {
+  }
+  std::vector<Pixel> data;
+  uint32_t          width;
+  uint32_t          height;
+  uint32_t          bytesPerPixel;
+  vk::Format        pixelFormat;
+};
+
+struct Texture
+{
+  Texture( Graphics& graphics, Pixmap pixmap ) : mGraphics( graphics ), mPixmap( pixmap )
+  {
+  }
+
+  bool Initialise()
+  {
+    // create image
+    mImage = Image::New( mGraphics,
+                         vk::ImageCreateInfo{}
+                           .setFormat( mPixmap.pixelFormat )
+                           .setInitialLayout( vk::ImageLayout::ePreinitialized )
+                           .setSamples( vk::SampleCountFlagBits::e1 )
+                           .setSharingMode( vk::SharingMode::eExclusive )
+                           .setUsage( vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst )
+                           .setExtent( {mPixmap.width, mPixmap.height, 1} )
+                           .setArrayLayers( 1 )
+                           .setImageType( vk::ImageType::e2D )
+                           .setTiling( vk::ImageTiling::eOptimal )
+                           .setMipLevels( 1 ) );
+
+    // allocate memory and bind to the image
+    auto& allocator = mGraphics.GetDeviceMemoryManager().GetDefaultAllocator();
+    mImage->BindMemory( allocator.Allocate( mImage, vk::MemoryPropertyFlagBits::eDeviceLocal ) );
+
+    // create transient buffer to copy data
+    auto buffer = Buffer::New( mGraphics,
+                               vk::BufferCreateInfo{}
+                                 .setUsage( vk::BufferUsageFlagBits::eTransferSrc )
+                                 .setSharingMode( vk::SharingMode::eExclusive )
+                                 .setSize( mPixmap.data.size()*sizeof(mPixmap.data[0]) ) );
+
+    buffer->BindMemory( allocator.Allocate( buffer, vk::MemoryPropertyFlagBits::eHostVisible ) );
+
+    // copy pixels to the buffer
+    auto ptr = buffer->GetMemoryHandle()->MapTyped<Pixel>();
+    std::copy( mPixmap.data.begin(), mPixmap.data.end(), ptr );
+    buffer->GetMemoryHandle()->Unmap();
+
+    // record copy and layout change
+    auto copy = vk::BufferImageCopy{}.setImageExtent( { mPixmap.width, mPixmap.height, 1 } )
+                         .setBufferImageHeight( mPixmap.height )
+                         .setBufferOffset( 0 )
+                         .setBufferRowLength( mPixmap.width * mPixmap.bytesPerPixel )
+                         .setImageExtent( { mPixmap.width, mPixmap.height, 1 } )
+                         .setImageOffset( { 0, 0, 0 } )
+                         .setImageSubresource(
+                           vk::ImageSubresourceLayers{}
+                           .setMipLevel( 0 )
+                           .setAspectMask( vk::ImageAspectFlagBits::eColor )
+                           .setLayerCount( 1 )
+                           .setBaseArrayLayer( 0 )
+                         );
+    mCommandPool = CommandPool::New( mGraphics );
+    mCommandBuffer = mCommandPool->NewCommandBuffer( true );
+    mCommandBuffer->Begin( vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
+
+    // change layout
+    auto barrier = std::vector<vk::ImageMemoryBarrier>{
+      mCommandBuffer->ImageLayoutTransitionBarrier( mImage, vk::ImageLayout::eTransferDstOptimal, vk::ImageAspectFlagBits::eColor )
+    };
+
+    // change layout to prepare image to transfer data
+    mCommandBuffer->PipelineBarrier( vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer,
+                                     {}, {}, {}, { barrier } );
+
+    // copy image
+    mCommandBuffer->CopyBufferToImage( buffer, mImage, vk::ImageLayout::ePreinitialized, { copy } );
+
+    // change layout to shader read-only optimal
+    mCommandBuffer->PipelineBarrier( vk::PipelineStageFlagBits::eVertexShader, vk::PipelineStageFlagBits::eVertexShader,
+                                     {}, {}, {}, {
+                                       mCommandBuffer->ImageLayoutTransitionBarrier( mImage, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageAspectFlagBits::eColor )
+                                     } );
+
+    mCommandBuffer->End();
+
+    // submit and wait till image is uploaded so temporary buffer can be destroyed safely
+    auto fence = Fence::New( mGraphics );
+    mGraphics.GetGraphicsQueue(0u).Submit( mCommandBuffer, fence );
+    fence->Wait();
+
+  }
+
+  Graphics&        mGraphics;
+  ImageRef         mImage;
+  ImageViewRef     mImageView;
+
+  CommandPoolRef    mCommandPool;
+  CommandBufferRef  mCommandBuffer; // primary buffer, executed independent
+
+  // layouts
+  vk::ImageLayout mOldLayout;
+  vk::ImageLayout mNewLayout;
+
+  // Command pool
+
+
+  Pixmap mPixmap;
+};
+
+/**
+ * Generates a random pixmap
+ * @param width
+ * @param height
+ * @return
+ */
+Pixmap GenerateTexture32BPPRGBA( uint32_t width, uint32_t height )
+{
+  std::vector<Pixel> data;
+  data.resize( width * height );
+
+  const Pixel WHITE     { 0xffffffff };
+  const Pixel BLACK     { 0x000000ff };
+  const Pixel RED       { 0xff0000ff };
+  const Pixel GREEN     { 0x00ff00ff };
+  const Pixel BLUE      { 0x0000ffff };
+
+  const Pixel COLORS[] = { WHITE, BLACK, RED, GREEN, BLUE };
+  const auto COLORS_COUNT = 5u;
+
+  for( auto y = 0u; y < height; ++y )
+  {
+    for( auto x = 0u; x < width; ++x )
+    {
+      data[ x + width * y ] = COLORS[ ((x*x)+(y*y)) % COLORS_COUNT];
+    }
+  }
+
+  return Pixmap{ data, width, height };
+}
+
+Pixmap LoadResourceImage( void* data, uint32_t width, uint32_t height, uint32_t bytesPerPixel )
+{
+  // todo: create Pixmap object
+}
+
+Texture CreateTexture( Graphics& graphics, Pixmap pixmap )
+{
+  return Texture( graphics, pixmap );
+}
+
+int TextureTestMain( Dali::Graphics::Vulkan::Graphics& graphics )
+{
+  auto pixmap = GenerateTexture32BPPRGBA( 1024, 1024 );
+  auto texture = Texture( graphics, pixmap );
+  texture.Initialise();
+  return 0;
+}
+
+} // namespace VulkanTest
\ No newline at end of file
index b443b69..1b36a45 100644 (file)
@@ -101,12 +101,6 @@ struct Buffer::Impl final
   vk::Buffer                            mBuffer;
 };
 
-/**
- *
- * @param graphics
- * @param size
- * @return
- */
 BufferRef Buffer::New(Graphics& graphics, size_t size, Type type)
 {
   auto usageFlags = vk::BufferUsageFlags{};
@@ -123,7 +117,7 @@ BufferRef Buffer::New(Graphics& graphics, size_t size, Type type)
   info.setSharingMode( vk::SharingMode::eExclusive );
   info.setSize( size );
   info.setUsage( usageFlags | vk::BufferUsageFlagBits::eTransferDst );
-  auto buffer = Handle<Buffer>( new Buffer(graphics, info) );
+  auto buffer = BufferRef( new Buffer(graphics, info) );
 
   if(buffer && buffer->mImpl->Initialise())
   {
@@ -132,6 +126,17 @@ BufferRef Buffer::New(Graphics& graphics, size_t size, Type type)
   return buffer;
 }
 
+BufferRef Buffer::New( Graphics& graphics, vk::BufferCreateInfo info )
+{
+  auto buffer = BufferRef( new Buffer(graphics, info) );
+  if( buffer && buffer->mImpl->Initialise() )
+  {
+    graphics.AddBuffer( buffer );
+    return buffer;
+  }
+  return BufferRef();
+}
+
 Buffer::Buffer(Graphics& graphics, const vk::BufferCreateInfo& createInfo)
 : VkManaged()
 {
index a83b005..9e508c0 100644 (file)
@@ -59,6 +59,14 @@ public:
   static BufferRef New( Graphics& graphics, size_t size, Type type );
 
   /**
+   *
+   * @param graphics
+   * @param info
+   * @return
+   */
+  static BufferRef New( Graphics& graphics, vk::BufferCreateInfo info );
+
+  /**
    * Returns buffer usage flags
    * @return
    */
index 027622d..d7ef0d1 100644 (file)
  */
 
 // INTERNAL INCLUDES
+#include <dali/graphics/vulkan/vulkan-types.h>
 #include <dali/graphics/vulkan/vulkan-buffer.h>
 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
 #include <dali/graphics/vulkan/vulkan-command-pool.h>
 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
 #include <dali/graphics/vulkan/vulkan-graphics.h>
 #include <dali/graphics/vulkan/vulkan-image.h>
+#include <dali/graphics/vulkan/vulkan-fence.h>
 #include <dali/graphics/vulkan/vulkan-pipeline.h>
 #include <dali/graphics/vulkan/vulkan-surface.h>
-#include <dali/graphics/vulkan/vulkan-types.h>
+#include <dali/graphics/vulkan/vulkan-framebuffer.h>
 
 namespace Dali
 {
@@ -44,6 +46,9 @@ struct CommandBuffer::Impl
 
   ~Impl()
   {
+    mResources.clear();
+    mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(),
+                                              1, &mCommandBuffer );
   }
 
   bool Initialise()
@@ -90,9 +95,10 @@ struct CommandBuffer::Impl
 
     if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
     {
-      // todo: sets render pass from 'default' surface, should be supplied from primary command buffer
-      // which has render pass associated within execution context
-      inheritance.setRenderPass( mGraphics.GetSurface( 0 ).GetRenderPass() );
+      // Render pass is obtained from the default framebuffer
+      // it's a legacy but little nicer
+      auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
+      inheritance.setRenderPass( swapchain->GetCurrentFramebuffer()->GetVkRenderPass() );
       info.setPInheritanceInfo( &inheritance );
     }
 
@@ -125,112 +131,6 @@ struct CommandBuffer::Impl
     mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
   }
 
-  void ImageLayoutTransition( vk::Image            image,
-                              vk::ImageLayout      oldLayout,
-                              vk::ImageLayout      newLayout,
-                              vk::ImageAspectFlags aspectMask )
-  {
-    // just push new image barrier until any command is being called or buffer recording ends.
-    // it will make sure we batch barriers together rather than calling cmdPipelineBarrier
-    // for each separately
-    vk::AccessFlags        srcAccessMask, dstAccessMask;
-    vk::PipelineStageFlags srcStageMask, dstStageMask;
-
-    // TODO: add other transitions
-    switch( oldLayout )
-    {
-      case vk::ImageLayout::eUndefined:
-      {
-        srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
-      }
-      break;
-      case vk::ImageLayout::ePresentSrcKHR:
-      {
-        srcStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput;
-        srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eColorAttachmentRead;
-      }
-      break;
-      case vk::ImageLayout::eColorAttachmentOptimal:
-      {
-        srcStageMask  = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
-        srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
-      }
-      break;
-      case vk::ImageLayout::eGeneral:
-      case vk::ImageLayout::eDepthStencilAttachmentOptimal:
-      case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
-      case vk::ImageLayout::eShaderReadOnlyOptimal:
-      case vk::ImageLayout::eTransferSrcOptimal:
-      case vk::ImageLayout::eTransferDstOptimal:
-      case vk::ImageLayout::ePreinitialized:
-      case vk::ImageLayout::eSharedPresentKHR:
-      {
-      }
-    }
-
-    switch( newLayout )
-    {
-      case vk::ImageLayout::eColorAttachmentOptimal:
-      {
-        dstStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput;// | */vk::PipelineStageFlagBits::eFragmentShader;
-        dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eMemoryWrite;
-        break;
-      }
-      case vk::ImageLayout::eDepthStencilAttachmentOptimal:
-      {
-        dstStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eEarlyFragmentTests;
-        dstAccessMask =
-          vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
-        break;
-      }
-      case vk::ImageLayout::ePresentSrcKHR:
-      {
-        dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
-        dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eMemoryRead;
-      }
-      case vk::ImageLayout::eGeneral:
-      case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
-      case vk::ImageLayout::eShaderReadOnlyOptimal:
-      case vk::ImageLayout::eTransferSrcOptimal:
-      case vk::ImageLayout::eTransferDstOptimal:
-      case vk::ImageLayout::ePreinitialized:
-      case vk::ImageLayout::eUndefined:
-      case vk::ImageLayout::eSharedPresentKHR:
-      {
-        break;
-      }
-    }
-
-    RecordImageLayoutTransition(
-      image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
-  }
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
-  void RecordImageLayoutTransition( vk::Image              image,
-                                    vk::AccessFlags        srcAccessMask,
-                                    vk::AccessFlags        dstAccessMask,
-                                    vk::PipelineStageFlags srcStageMask,
-                                    vk::PipelineStageFlags dstStageMask,
-                                    vk::ImageLayout        oldLayout,
-                                    vk::ImageLayout        newLayout,
-                                    vk::ImageAspectFlags   aspectMask )
-  {
-    vk::ImageSubresourceRange subres;
-    subres.setLayerCount( 1 ).setBaseMipLevel( 0 ).setBaseArrayLayer( 0 ).setLevelCount( 1 ).setAspectMask(
-      aspectMask );
-
-    auto barrier = vk::ImageMemoryBarrier{};
-    barrier.setImage( image )
-      .setSubresourceRange( subres )
-      .setSrcAccessMask( srcAccessMask )
-      .setDstAccessMask( dstAccessMask )
-      .setOldLayout( oldLayout )
-      .setNewLayout( newLayout );
-    ;
-    // todo: implement barriers batching
-    mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, vk::DependencyFlags{}, nullptr, nullptr, barrier );
-  }
 #pragma GCC diagnostic pop
 
   /** Push wait semaphores */
@@ -327,17 +227,18 @@ struct CommandBuffer::Impl
   // RENDER PASS
   void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
   {
-    auto& surface     = mGraphics.GetSurface( framebufferId );
-    auto  renderPass  = surface.GetRenderPass();
-    auto  frameBuffer = surface.GetFramebuffer( bufferIndex );
-    auto  clearValues = surface.GetClearValues();
+    auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
+    auto surface = mGraphics.GetSurface( 0u );
+    auto frameBuffer = swapchain->GetCurrentFramebuffer();
+    auto renderPass = frameBuffer->GetVkRenderPass();
+    auto clearValues = frameBuffer->GetDefaultClearValues();
 
     auto info = vk::RenderPassBeginInfo{};
-    info.setFramebuffer( frameBuffer );
+    info.setFramebuffer( frameBuffer->GetVkFramebuffer() );
     info.setRenderPass( renderPass );
     info.setClearValueCount( U32( clearValues.size() ) );
     info.setPClearValues( clearValues.data() );
-    info.setRenderArea( vk::Rect2D( {0, 0}, surface.GetSize() ) );
+    info.setRenderArea( vk::Rect2D( {0, 0}, surface->GetSize() ) );
 
     mCurrentRenderPass = renderPass;
     mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
@@ -368,6 +269,58 @@ struct CommandBuffer::Impl
     mCommandBuffer.executeCommands( vkBuffers );
   }
 
+  void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
+                        vk::PipelineStageFlags dstStageMask,
+                        vk::DependencyFlags dependencyFlags,
+                        std::vector<vk::MemoryBarrier> memoryBarriers,
+                        std::vector<vk::BufferMemoryBarrier> bufferBarriers,
+                        std::vector<vk::ImageMemoryBarrier> imageBarriers )
+  {
+    /*
+     * Track resources
+     */
+    if( !imageBarriers.empty() )
+    {
+      for( auto&& imageBarrier : imageBarriers )
+      {
+        ImageRef imageResource{};
+        if( imageResource = mGraphics.FindImage( imageBarrier.image ) )
+        {
+          PushResource( imageResource );
+        }
+      }
+    }
+    //@ todo other resource tracking
+
+    mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
+  }
+
+  void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
+  {
+    PushResource( srcBuffer );
+    PushResource( dstImage );
+
+    mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
+  }
+
+  vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
+                                                      const vk::AccessFlags&        srcAccessMask,
+                                                      const vk::AccessFlags&        dstAccessMask,
+                                                      vk::ImageLayout        oldLayout,
+                                                      vk::ImageLayout        newLayout,
+                                                      const vk::ImageAspectFlags&   aspectMask
+  ) const
+  {
+    return vk::ImageMemoryBarrier{}
+         .setNewLayout( newLayout )
+         .setImage( image->GetVkImage() )
+         .setOldLayout( oldLayout )
+         .setSrcAccessMask( srcAccessMask )
+         .setDstAccessMask( dstAccessMask )
+         .setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
+  }
+
+
   Graphics&                     mGraphics;
   CommandPool&                  mOwnerCommandPool;
   vk::CommandBufferAllocateInfo mAllocateInfo{};
@@ -385,6 +338,8 @@ struct CommandBuffer::Impl
 
   vk::RenderPass mCurrentRenderPass;
 
+  FenceRef       mFinishedFence;
+
   bool mRecording{false};
 };
 
@@ -429,29 +384,11 @@ void CommandBuffer::Free()
   mImpl->Free();
 }
 
-/** Records image layout transition barrier for one image */
-void CommandBuffer::ImageLayoutTransition( vk::Image            image,
-                                           vk::ImageLayout      oldLayout,
-                                           vk::ImageLayout      newLayout,
-                                           vk::ImageAspectFlags aspectMask )
+void CommandBuffer::OnRelease( uint32_t refcount )
 {
-  mImpl->ImageLayoutTransition( image, oldLayout, newLayout, aspectMask );
+  VkManaged::OnRelease( refcount );
 }
 
-/*
-void CommandBuffer::RecordImageLayoutTransition( vk::Image              image,
-                                                 vk::AccessFlags        srcAccessMask,
-                                                 vk::AccessFlags        dstAccessMask,
-                                                 vk::PipelineStageFlags srcStageMask,
-                                                 vk::PipelineStageFlags dstStageMask,
-                                                 vk::ImageLayout        oldLayout,
-                                                 vk::ImageLayout        newLayout,
-                                                 vk::ImageAspectFlags   aspectMask )
-{
-  mImpl->RecordImageLayoutTransition(
-    image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
-}
-*/
 /** Push wait semaphores */
 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
                                         const std::vector<vk::PipelineStageFlags>& stages )
@@ -561,6 +498,129 @@ void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<
   mImpl->ExecuteCommands( commandBuffers );
 }
 
+void CommandBuffer::PipelineBarrier( vk::PipelineStageFlags srcStageMask,
+                      vk::PipelineStageFlags dstStageMask,
+                      vk::DependencyFlags dependencyFlags,
+                      std::vector<vk::MemoryBarrier> memoryBarriers,
+                      std::vector<vk::BufferMemoryBarrier> bufferBarriers,
+                      std::vector<vk::ImageMemoryBarrier> imageBarriers )
+{
+  mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
+}
+
+void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
+                                       vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
+{
+  mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
+}
+
+vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
+                                                     vk::AccessFlags        srcAccessMask,
+                                                     vk::AccessFlags        dstAccessMask,
+                                                     vk::ImageLayout        oldLayout,
+                                                     vk::ImageLayout        newLayout,
+                                                     vk::ImageAspectFlags   aspectMask
+) const
+{
+  return mImpl->ImageLayoutTransitionBarrier( image,
+                                              srcAccessMask, dstAccessMask,
+                                              oldLayout, newLayout,
+                                              aspectMask  );
+}
+
+vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
+                                                     vk::ImageLayout        newLayout,
+                                                     vk::ImageAspectFlags   aspectMask
+) const
+{
+
+  vk::AccessFlags  srcAccessMask, dstAccessMask;
+  vk::PipelineStageFlags srcStageMask, dstStageMask;
+
+  auto oldLayout = image->GetVkImageLayout();
+
+  switch( oldLayout )
+  {
+    case vk::ImageLayout::ePreinitialized:
+    case vk::ImageLayout::eUndefined:
+    {
+      srcAccessMask = {};
+      srcStageMask  = vk::PipelineStageFlagBits::eTopOfPipe;
+      break;
+    }
+    case vk::ImageLayout::ePresentSrcKHR:
+    {
+      srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
+      srcStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput;
+      break;
+    }
+    case vk::ImageLayout::eTransferSrcOptimal:
+    {
+      srcAccessMask = vk::AccessFlagBits::eMemoryRead;
+      srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eTransferDstOptimal:
+    {
+      srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
+      srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eGeneral:
+    case vk::ImageLayout::eColorAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
+    case vk::ImageLayout::eShaderReadOnlyOptimal:
+    case vk::ImageLayout::eSharedPresentKHR:
+    {
+      break;
+    }
+  }
+
+  switch( newLayout )
+  {
+    case vk::ImageLayout::ePresentSrcKHR:
+    {
+      dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
+      dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
+      break;
+    }
+    case vk::ImageLayout::eTransferSrcOptimal:
+    {
+      dstAccessMask = vk::AccessFlagBits::eMemoryRead;
+      dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eTransferDstOptimal:
+    {
+      dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
+      dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eShaderReadOnlyOptimal:
+    {
+      dstAccessMask = vk::AccessFlagBits::eMemoryRead;
+      dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
+      break;
+    }
+    case vk::ImageLayout::eUndefined:
+    case vk::ImageLayout::eGeneral:
+    case vk::ImageLayout::eColorAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
+    case vk::ImageLayout::ePreinitialized:
+    case vk::ImageLayout::eSharedPresentKHR:
+    {
+      break;
+    }
+  }
+
+  return mImpl->ImageLayoutTransitionBarrier( image,
+                                              srcAccessMask, dstAccessMask,
+                                              oldLayout, newLayout,
+                                              aspectMask  );
+}
+
 } // namespace Vulkan
 } // namespace Graphics
 } // namespace Dali
index 2dab9f7..3efd080 100644 (file)
@@ -55,9 +55,6 @@ public:
   /** Free command buffer */
   void Free();
 
-  /** Records image layout transition barrier for one image */
-  void ImageLayoutTransition(vk::Image image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::ImageAspectFlags aspectMask);
-
   /** Push wait semaphores */
   void PushWaitSemaphores(const std::vector< vk::Semaphore >&          semaphores,
                           const std::vector< vk::PipelineStageFlags >& stages);
@@ -187,32 +184,62 @@ public:
   void EndRenderPass();
 
   /**
+   * Records pipeline barrier
+   * @param srcStageMask
+   * @param dstStageMask
+   * @param dependencyFlags
+   * @param memoryBarriers
+   * @param bufferBarriers
+   * @param imageBarriers
+   */
+  void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
+                        vk::PipelineStageFlags dstStageMask,
+                        vk::DependencyFlags dependencyFlags,
+                        std::vector<vk::MemoryBarrier> memoryBarriers,
+                        std::vector<vk::BufferMemoryBarrier> bufferBarriers,
+                        std::vector<vk::ImageMemoryBarrier> imageBarriers );
+
+  /**
    * Executes secondary command buffers within primary command buffer
    * @param commandBuffers
    */
   void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers );
 
-private:
+  /**
+   * Copies buffer into the specified image
+   * @param srcBuffer
+   * @param dstImage
+   * @param dtsLayout
+   * @param regions
+   */
+  void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout,
+                          std::vector<vk::BufferImageCopy> regions );
+
+  void OnRelease( uint32_t refcount ) override;
 
   /**
-   *
+   * Creates layout transition barrier
+   * @return
+   */
+  vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
+                                                  vk::AccessFlags        srcAccessMask,
+                                                  vk::AccessFlags        dstAccessMask,
+                                                  vk::ImageLayout        oldLayout,
+                                                  vk::ImageLayout        newLayout,
+                                                  vk::ImageAspectFlags   aspectMask
+  ) const;
+
+  /**
+   * Simplified version of memory barrier generation based on data stored inside the Image
    * @param image
-   * @param srcAccessMask
-   * @param dstAccessMask
-   * @param srcStageMask
-   * @param dstStageMask
-   * @param oldLayout
    * @param newLayout
    * @param aspectMask
+   * @return
    */
-  void RecordImageLayoutTransition(vk::Image             image,
-                                   vk::AccessFlags        srcAccessMask,
-                                   vk::AccessFlags        dstAccessMask,
-                                   vk::PipelineStageFlags srcStageMask,
-                                   vk::PipelineStageFlags dstStageMask,
-                                   vk::ImageLayout        oldLayout,
-                                   vk::ImageLayout        newLayout,
-                                   vk::ImageAspectFlags   aspectMask);
+  vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
+                                                       vk::ImageLayout        newLayout,
+                                                       vk::ImageAspectFlags   aspectMask
+  ) const;
 
 private:
 
index 7da7982..77a7ddc 100644 (file)
@@ -63,7 +63,7 @@ struct CommandPool::Impl
     mAllocatedCommandBuffers.clear();
   }
 
-  Handle<CommandBuffer> NewCommandBuffer( const vk::CommandBufferAllocateInfo& allocateInfo )
+  CommandBufferRef NewCommandBuffer( const vk::CommandBufferAllocateInfo& allocateInfo )
   {
     vk::CommandBufferAllocateInfo info( allocateInfo );
     info.setCommandPool( mCommandPool );
@@ -73,12 +73,30 @@ struct CommandPool::Impl
     return mAllocatedCommandBuffers.back();
   }
 
+  bool ReleaseCommandBuffer( const CommandBufferRef& buffer, bool forceRelease )
+  {
+    if( buffer.GetRefCount() == 2 )
+    {
+      for(auto&& cmdBuf : mAllocatedCommandBuffers )
+      {
+        if(cmdBuf == buffer )
+        {
+          // fixme: should remove from list but in future the cache of command buffer will work
+          // different
+          cmdBuf.Reset();
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   Graphics& mGraphics;
   CommandPool& mInterface;
   vk::CommandPoolCreateInfo mCreateInfo;
   vk::CommandPool mCommandPool;
 
-  std::vector<Handle<CommandBuffer>> mAllocatedCommandBuffers;
+  std::vector<CommandBufferRef> mAllocatedCommandBuffers;
 };
 
 /**
@@ -143,6 +161,11 @@ void CommandPool::Reset( bool releaseResources )
   mImpl->Reset( releaseResources );
 }
 
+bool CommandPool::ReleaseCommandBuffer( CommandBufferRef buffer, bool forceRelease )
+{
+  return mImpl->ReleaseCommandBuffer( buffer, forceRelease );
+}
+
 } // namespace Vulkan
 } // namespace Graphics
 } // namespace Dali
index 9614722..787bc77 100644 (file)
@@ -86,6 +86,13 @@ public:
    */
   CommandBufferRef NewCommandBuffer( bool isPrimary = true );
 
+  /**
+   * Releases command buffer
+   * @param buffer
+   * @return
+   */
+  bool ReleaseCommandBuffer( CommandBufferRef buffer, bool forceRelease );
+
 public:
 
   bool OnDestroy() override;
index 0456313..f3ab656 100644 (file)
@@ -19,6 +19,7 @@
 #include <dali/graphics/vulkan/vulkan-graphics.h>
 #include <dali/graphics/vulkan/vulkan-image.h>
 
+
 namespace Dali
 {
 namespace Graphics
@@ -30,126 +31,130 @@ struct Framebuffer::Impl
   Impl( Framebuffer& owner, Graphics& graphics, uint32_t width, uint32_t height )
   : mInterface( owner ), mGraphics( graphics ), mColorImageViewAttachments{}, mDepthStencilImageViewAttachment()
   {
+    mWidth = width;
+    mHeight = height;
   }
 
-  // Framebuffer creation may be deferred
+  // creating render pass may happen either as deferred or
+  // when framebuffer is initialised into immutable state
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
   bool Initialise()
   {
-    if( mInitialised )
+    mAttachmentReference.clear();
+    mAttachmentDescription.clear();
+    mDefaultClearValues.clear();
+    /*
+     * COLOR ATTACHMENTS
+     */
+    auto attachments         = std::vector<vk::ImageView>{};
+    auto colorAttachmentSize = 0u;
+    for( auto&& colorAttachment : mColorImageViewAttachments )
     {
-      return true;
+      auto attRef = vk::AttachmentReference{};
+      attRef.setLayout( vk::ImageLayout::eColorAttachmentOptimal );
+      attRef.setAttachment( colorAttachmentSize++ );
+      mAttachmentReference.emplace_back( attRef );
+      attachments.emplace_back( colorAttachment->GetVkImageView() );
+
+      vk::AttachmentDescription attDesc{};
+      attDesc.setSamples( vk::SampleCountFlagBits::e1 )
+        .setInitialLayout( vk::ImageLayout::eColorAttachmentOptimal )
+        .setFormat( colorAttachment->GetImage()->GetVkFormat() )
+        .setStencilStoreOp( vk::AttachmentStoreOp::eDontCare )
+        .setStencilLoadOp( vk::AttachmentLoadOp::eDontCare )
+        .setLoadOp( vk::AttachmentLoadOp::eClear )
+        .setStoreOp( vk::AttachmentStoreOp::eStore )
+        .setFinalLayout( vk::ImageLayout::ePresentSrcKHR );
+
+      mAttachmentDescription.emplace_back( attDesc );
+
+      // update clear color values
+      vk::ClearColorValue clear;
+      clear.setFloat32( {0.0f, 0.0f, 0.0f, 1.0f} );
+      mDefaultClearValues.emplace_back( clear );
     }
 
-    if( !Validate() )
+    /*
+     * DEPTH-STENCIL ATTACHMENT
+     */
+    if( mDepthStencilImageViewAttachment )
     {
-      return false;
+      auto attRef = vk::AttachmentReference{};
+      attRef.setLayout( vk::ImageLayout::eDepthStencilAttachmentOptimal );
+      attRef.setAttachment( colorAttachmentSize );
+      mAttachmentReference.emplace_back( attRef );
+      attachments.emplace_back( mDepthStencilImageViewAttachment->GetVkImageView() );
+
+      vk::AttachmentDescription attDesc{};
+      attDesc.setSamples( vk::SampleCountFlagBits::e1 )
+             .setInitialLayout( vk::ImageLayout::eDepthStencilAttachmentOptimal )
+             .setFormat( mDepthStencilImageViewAttachment->GetImage()->GetVkFormat() )
+             .setStencilStoreOp( vk::AttachmentStoreOp::eDontCare )
+             .setStencilLoadOp( vk::AttachmentLoadOp::eDontCare )
+             .setLoadOp( vk::AttachmentLoadOp::eClear )
+             .setStoreOp( vk::AttachmentStoreOp::eDontCare )
+             .setFinalLayout( vk::ImageLayout::eDepthStencilAttachmentOptimal );
+      mAttachmentDescription.emplace_back( attDesc );
+
+      // update clear depth/stencil values
+      vk::ClearDepthStencilValue clear;
+      clear.setDepth( 0.0f ).setStencil( 1.0f );
+      mDefaultClearValues.emplace_back( clear );
     }
 
     /*
-    auto attRef = vk::AttachmentReference{};
-    attRef.setLayout();
-    attRef.setAttachment();
-
-    // creating single subpass per framebuffer
-    auto subpassDesc = vk::SubpassDescription{};
-    subpassDesc.setPipelineBindPoint( vk::PipelineBindPoint::eGraphics );
-    subpassDesc.setColorAttachmentCount(0);
-    subpassDesc.setInputAttachmentCount(0);
-    subpassDesc.setPDepthStencilAttachment(nullptr);
-    subpassDesc.setPColorAttachments( nullptr );
-    subpassDesc.setPInputAttachments( nullptr );
-    subpassDesc.setPPreserveAttachments( nullptr );
-    subpassDesc.setPResolveAttachments( nullptr );
-
-
-    auto rpInfo = vk::RenderPassCreateInfo{};
-    rpInfo.setAttachmentCount( mAttachments.size() );
-    //rpInfo.setPAttachments( )
-    rpInfo.setDependencyCount( 0 );
-    rpInfo.setPDependencies( nullptr );
-    rpInfo.setPSubpasses( &subpassDesc );
-    rpInfo.setSubpassCount( 1 );
-
-    auto fbInfo = vk::FramebufferCreateInfo{};
-    fbInfo.setWidth( mWidth );
-    fbInfo.setHeight( mHeight );
-    //fbInfo.setRenderPass( )
-    //fbInfo.setAttachmentCount( 0 );
-    //fbInfo.setPAttachments( ImageViews );
-    */
-    mInitialised = true;
-  }
-
-  // creating render pass may happen either as deferred or
-  // when framebuffer is initialised into immutable state
-  void CreateRenderPass()
-  {
-    // for each attachment...
-#if 0
-    auto attRef = vk::AttachmentReference{};
-
-    // 1. Need to know layout during render pass ( Image::GetLayout() )
-    // 2. Usually it's going to be:
-    //    - color_attachment_optimal
-    //    - depth_stencil_attachment_optimal
-    //attRef.setLayout();
-    //attRef.setAttachment();
-
-    // Single subpass support, all attachments used
-    // TODO: input, preserve, resolve
-    // TODO: create subpasses
-
+     * SUBPASS
+     */
     // creating single subpass per framebuffer
     auto subpassDesc = vk::SubpassDescription{};
     subpassDesc.setPipelineBindPoint( vk::PipelineBindPoint::eGraphics );
-    subpassDesc.setColorAttachmentCount( 0 );
-    subpassDesc.setInputAttachmentCount( 0 );
-    subpassDesc.setPDepthStencilAttachment( nullptr );
-    subpassDesc.setPColorAttachments( nullptr );
-    subpassDesc.setPInputAttachments( nullptr );
-    subpassDesc.setPPreserveAttachments( nullptr );
-    subpassDesc.setPResolveAttachments( nullptr );
+    subpassDesc.setColorAttachmentCount( colorAttachmentSize );
+    if( mDepthStencilImageViewAttachment )
+    {
+      subpassDesc.setPDepthStencilAttachment( &mAttachmentReference[colorAttachmentSize] );
+    }
+    subpassDesc.setPColorAttachments( &mAttachmentReference[0] );
 
+    /*
+     * RENDERPASS
+     */
     // create compatible render pass
     auto rpInfo = vk::RenderPassCreateInfo{};
-    //rpInfo.setAttachmentCount( mAttachments.size() );
-    //rpInfo.setPAttachments( )
-    rpInfo.setDependencyCount( 0 );
-    rpInfo.setPDependencies( nullptr );
+    rpInfo.setAttachmentCount( U32(mAttachmentDescription.size()) );
+    rpInfo.setPAttachments( mAttachmentDescription.data() );
     rpInfo.setPSubpasses( &subpassDesc );
     rpInfo.setSubpassCount( 1 );
-#endif
-  }
-
-  void InitialiseAttachments()
-  {
-    ImageRef                attachment;
-    vk::ImageViewCreateInfo info;
-    info.setViewType( vk::ImageViewType::e2D );
-    info.setSubresourceRange( //get layercount, get level count
-      vk::ImageSubresourceRange{}.setLevelCount( 1 ).setLayerCount( 1 ).setBaseMipLevel( 0 ).setBaseArrayLayer( 0 ) );
-    info.setImage( attachment->GetVkImage() ); //
-    info.setComponents( vk::ComponentMapping(
-      vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB, vk::ComponentSwizzle::eA ) );
-    info.setFormat( vk::Format::eD16Unorm ); // get format
-
-    //ImageViewRef ref = ImageView::New( attachment );
-  }
-
-  void CreateFramebuffer()
-  {
-    // assert if framebuffer is already created
-    InitialiseAttachments();
+    mVkRenderPass = VkAssert( mGraphics.GetDevice().createRenderPass( rpInfo, mGraphics.GetAllocator() ));
 
+    /*
+     * FRAMEBUFFER
+     */
     vk::FramebufferCreateInfo info;
     info.setRenderPass( mVkRenderPass )
-      .setPAttachments( nullptr ) // attach imageviews, imageviews are created from supplied images
-      .setLayers( 1 )
-      .setWidth( mWidth )
-      .setHeight( mHeight )
-      .setAttachmentCount( 1 );
+        .setPAttachments( attachments.data() )
+        .setLayers( 1 )
+        .setWidth( mWidth )
+        .setHeight( mHeight )
+        .setAttachmentCount( U32(attachments.size()) );
 
     mVkFramebuffer = VkAssert( mGraphics.GetDevice().createFramebuffer( info, mGraphics.GetAllocator() ) );
+
+    return true;
+  }
+#pragma GCC diagnostic pop
+
+  /**
+   * Creates immutable framebuffer object
+   */
+  bool Commit()
+  {
+    if(!mInitialised)
+    {
+      mInitialised = Initialise();
+      return mInitialised;
+    }
+    return false;
   }
 
   void SetAttachment( ImageViewRef imageViewRef, Framebuffer::AttachmentType type, uint32_t index )
@@ -170,7 +175,7 @@ struct Framebuffer::Impl
     }
   }
 
-  ImageViewRef GetAttachmentImageView( AttachmentType type, uint32_t index ) const
+  ImageViewRef GetAttachment( AttachmentType type, uint32_t index ) const
   {
     switch( type )
     {
@@ -193,18 +198,63 @@ struct Framebuffer::Impl
     return ImageViewRef();
   }
 
-  bool Validate()
+  std::vector<ImageViewRef> GetAttachments( AttachmentType type ) const
   {
-    if( mWidth == 0u || mHeight == 0 )
+    std::vector<ImageViewRef> retval{};
+    switch( type )
     {
-      return false;
+      case AttachmentType::COLOR:
+      {
+        retval.insert( retval.end(), mColorImageViewAttachments.begin(), mColorImageViewAttachments.end() );
+        return retval;
+      }
+      case AttachmentType::DEPTH_STENCIL:
+      {
+        retval.push_back( mDepthStencilImageViewAttachment );
+        return retval;
+      }
+      case AttachmentType::DEPTH:
+      case AttachmentType::INPUT:
+      case AttachmentType::RESOLVE:
+      case AttachmentType::PRESERVE:
+      {
+        return retval;
+      }
+    }
+    return retval;
+  }
+
+  uint32_t GetAttachmentCount( AttachmentType type ) const
+  {
+    std::vector<ImageViewRef> retval{};
+    switch( type )
+    {
+      case AttachmentType::COLOR:
+      {
+        return U32(mColorImageViewAttachments.size());
+      }
+      case AttachmentType::DEPTH_STENCIL:
+      {
+        return mDepthStencilImageViewAttachment ? 1u : 0u;
+      }
+      case AttachmentType::DEPTH:
+      case AttachmentType::INPUT:
+      case AttachmentType::RESOLVE:
+      case AttachmentType::PRESERVE:
+      {
+        return 0u;
+      }
     }
+    return 0u;
   }
 
-  ~Impl()
+  const std::vector<vk::ClearValue>& GetDefaultClearValues() const
   {
+    return mDefaultClearValues;
   }
 
+  ~Impl() = default;
+
   vk::RenderPass GetVkRenderPass() const
   {
     return mVkRenderPass;
@@ -226,12 +276,23 @@ struct Framebuffer::Impl
   vk::Framebuffer           mVkFramebuffer;
   vk::RenderPass            mVkRenderPass;
 
+  // attachment references for the main subpass
+  std::vector<vk::AttachmentReference>   mAttachmentReference;
+  std::vector<vk::AttachmentDescription> mAttachmentDescription;
+
+  std::vector<vk::ClearValue> mDefaultClearValues;
   bool mInitialised{false};
 };
 
 FramebufferRef Framebuffer::New( Graphics& graphics, uint32_t width, uint32_t height )
 {
-  return FramebufferRef();
+  FramebufferRef ref( new Framebuffer( graphics, width, height ) );
+  return ref;
+}
+
+Framebuffer::Framebuffer( Graphics& graphics, uint32_t width, uint32_t height )
+{
+  mImpl = std::make_unique<Impl>( *this, graphics, width, height );
 }
 
 void Framebuffer::SetAttachment( ImageViewRef imageViewRef, Framebuffer::AttachmentType type, uint32_t index )
@@ -249,9 +310,39 @@ uint32_t Framebuffer::GetHeight() const
   return mImpl->mHeight;
 }
 
-Handle<ImageView> Framebuffer::GetAttachmentImageView( AttachmentType type, uint32_t index ) const
+ImageViewRef Framebuffer::GetAttachment( AttachmentType type, uint32_t index ) const
+{
+  return mImpl->GetAttachment( type, index );
+}
+
+std::vector<ImageViewRef> Framebuffer::GetAttachments( AttachmentType type ) const
+{
+  return mImpl->GetAttachments( type );
+}
+
+uint32_t Framebuffer::GetAttachmentCount( AttachmentType type ) const
+{
+  return mImpl->GetAttachmentCount( type );
+}
+
+void Framebuffer::Commit()
+{
+  mImpl->Commit();
+}
+
+vk::RenderPass Framebuffer::GetVkRenderPass() const
+{
+  return mImpl->mVkRenderPass;
+}
+
+vk::Framebuffer Framebuffer::GetVkFramebuffer() const
+{
+  return mImpl->mVkFramebuffer;
+}
+
+const std::vector<vk::ClearValue>& Framebuffer::GetDefaultClearValues() const
 {
-  return mImpl->GetAttachmentImageView( type, index );
+  return mImpl->GetDefaultClearValues();
 }
 
 } // Namespace Vulkan
index 64ecf53..b0ec55b 100644 (file)
@@ -54,15 +54,27 @@ public:
 
   uint32_t GetHeight() const;
 
-  ImageViewRef GetAttachmentImageView( AttachmentType type, uint32_t index ) const;
+  ImageViewRef GetAttachment( AttachmentType type, uint32_t index ) const;
+
+  std::vector<ImageViewRef> GetAttachments( AttachmentType type ) const;
+
+  uint32_t GetAttachmentCount( AttachmentType type ) const;
 
   void SetAttachment( ImageViewRef imageViewRef, Framebuffer::AttachmentType type, uint32_t index );
 
+  void Commit();
+
+  vk::RenderPass GetVkRenderPass() const;
 
+  vk::Framebuffer GetVkFramebuffer() const;
+
+  const std::vector<vk::ClearValue>& GetDefaultClearValues() const;
 
 private:
 
-  class Impl;
+  Framebuffer( Graphics& graphics, uint32_t width, uint32_t height );
+
+  struct Impl;
   std::unique_ptr<Impl> mImpl;
 
 };
index 8f715e6..ac89fc1 100644 (file)
@@ -16,6 +16,7 @@
 #include <dali/graphics/vulkan/vulkan-graphics.h>
 #include <dali/graphics/vulkan/vulkan-pipeline.h>
 #include <dali/graphics/vulkan/vulkan-shader.h>
+#include <dali/graphics/vulkan/vulkan-framebuffer.h>
 #include <dali/graphics/vulkan/vulkan-surface.h>
 
 using namespace glm;
@@ -71,16 +72,15 @@ struct Controller::Impl
 
     mDebugPipelineState.descriptorPool = CreateDescriptorPool();
 
-    const float halfWidth = 0.5f;
+    const float halfWidth  = 0.5f;
     const float halfHeight = 0.5f;
-//#if 0
-    const vec3 VERTICES[4] =
-                  {
-                    { halfWidth,  halfHeight, 0.0f },
-                    { halfWidth, -halfHeight, 0.0f },
-                    { -halfWidth,  halfHeight, 0.0f },
-                    { -halfWidth, -halfHeight, 0.0f },
-                  };
+    //#if 0
+    const vec3 VERTICES[4] = {
+      {halfWidth, halfHeight, 0.0f},
+      {halfWidth, -halfHeight, 0.0f},
+      {-halfWidth, halfHeight, 0.0f},
+      {-halfWidth, -halfHeight, 0.0f},
+    };
 //#endif
 #if 0
     const vec3 VERTICES[4] = {
@@ -127,7 +127,7 @@ struct Controller::Impl
     pipeline->SetShader( state.vertexShader, Shader::Type::VERTEX );
     pipeline->SetShader( state.fragmentShader, Shader::Type::FRAGMENT );
 
-    auto size = mGraphics.GetSurface( 0u ).GetSize();
+    auto size = mGraphics.GetSurface( 0u )->GetSize();
     pipeline->SetViewport( 0, 0, static_cast<float>( size.width ), static_cast<float>( size.height ) );
 
     pipeline->SetVertexInputState(
@@ -170,9 +170,9 @@ struct Controller::Impl
     for( auto&& buf : bufferList.Get() )
     {
       // TODO: @todo implement minimum offset!
-      const uint32_t sizeOfUniformBuffer = U32((buf->GetSize() / drawcalls.Get()));
-      const uint32_t uniformBlockOffsetStride = ((sizeOfUniformBuffer / 256)+1)*256;
-      const uint32_t uniformBlockMemoryNeeded = U32(uniformBlockOffsetStride*drawcalls.Get());
+      const uint32_t sizeOfUniformBuffer      = U32( ( buf->GetSize() / drawcalls.Get() ) );
+      const uint32_t uniformBlockOffsetStride = ( ( sizeOfUniformBuffer / 256 ) + 1 ) * 256;
+      const uint32_t uniformBlockMemoryNeeded = U32( uniformBlockOffsetStride * drawcalls.Get() );
 
       // create buffer if doesn't exist
       if( !state.uniformBuffer0 )
@@ -193,16 +193,16 @@ struct Controller::Impl
         mat4 mvp;
         vec4 color;
         vec3 size;
-      } __attribute__((aligned(16)));
+      } __attribute__( ( aligned( 16 ) ) );
 
       auto memory = state.uniformBuffer0->GetMemoryHandle();
       auto outPtr = memory->MapTyped<char>();
       for( auto i = 0u; i < drawcalls.Get(); ++i )
       {
         // copy chunk of data
-        UB* inputData = (reinterpret_cast<UB*>(buf->GetDataBase())) + i;
-        UB* outputData = (reinterpret_cast<UB*>(outPtr + (i*uniformBlockOffsetStride)));
-        *outputData = *inputData;
+        UB* inputData  = ( reinterpret_cast<UB*>( buf->GetDataBase() ) ) + i;
+        UB* outputData = ( reinterpret_cast<UB*>( outPtr + ( i * uniformBlockOffsetStride ) ) );
+        *outputData    = *inputData;
 
         auto descriptorSets = state.descriptorPool->AllocateDescriptorSets(
           vk::DescriptorSetAllocateInfo{}.setDescriptorSetCount( 1 ).setPSetLayouts(
@@ -226,7 +226,7 @@ struct Controller::Impl
       memory->Unmap();
 
       // execute buffer
-      mGraphics.GetSurface( 0u ).GetCurrentCommandBuffer()->ExecuteCommands( executeCommands );
+      mGraphics.GetSwapchainForFBID( 0u )->GetPrimaryCommandBuffer()->ExecuteCommands( executeCommands );
 
       // break, one pass only
       break;
@@ -235,8 +235,10 @@ struct Controller::Impl
 #pragma GCC diagnostic pop
   void BeginFrame()
   {
-    auto& surface = mGraphics.GetSurface( 0u );
-    surface.AcquireNextImage();
+    auto surface = mGraphics.GetSurface( 0u );
+
+    auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
+    swapchain->AcquireNextFramebuffer();
 
     // rewind pools
     mDebugPipelineState.drawPoolIndex = 0u;
@@ -246,8 +248,8 @@ struct Controller::Impl
 
   void EndFrame()
   {
-    auto& surface = mGraphics.GetSurface( 0u );
-    surface.Present();
+    auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
+    swapchain->Present();
   }
 
   DescriptorPoolRef CreateDescriptorPool()
index f9eb369..655272f 100644 (file)
@@ -58,16 +58,17 @@ namespace Vulkan
 const auto VALIDATION_LAYERS = std::vector< const char* >{
 
   //"VK_LAYER_LUNARG_screenshot",           // screenshot
-  "VK_LAYER_RENDERDOC_Capture",
-  "VK_LAYER_LUNARG_parameter_validation", // parameter
+  //"VK_LAYER_RENDERDOC_Capture",
+  //"VK_LAYER_LUNARG_parameter_validation", // parameter
   //"VK_LAYER_LUNARG_vktrace",              // vktrace ( requires vktrace connection )
-  "VK_LAYER_LUNARG_monitor",             // monitor
+  //"VK_LAYER_LUNARG_monitor",             // monitor
   "VK_LAYER_LUNARG_swapchain",           // swapchain
   "VK_LAYER_GOOGLE_threading",           // threading
   "VK_LAYER_LUNARG_api_dump",            // api
   "VK_LAYER_LUNARG_object_tracker",      // objects
   "VK_LAYER_LUNARG_core_validation",     // core
   "VK_LAYER_GOOGLE_unique_objects",      // unique objects
+  "VK_LAYER_GOOGLE_unique_objects",      // unique objects
   "VK_LAYER_LUNARG_standard_validation", // standard
 };
 
@@ -280,18 +281,59 @@ void Graphics::GetQueueFamilyProperties()
 
 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
 {
-  const auto vkFactory = dynamic_cast< const VkSurfaceFactory* >(surfaceFactory.get());
-  if(!vkFactory)
+  // create surface from the factory
+  auto surfaceRef = Surface::New( *this, std::move(surfaceFactory) );
+
+  if( surfaceRef->Create() )
   {
-    return FBID{0u};
+
+    // map surface to FBID
+    auto fbid = ++mBaseFBID;
+    mSurfaceFBIDMap[fbid] = SwapchainSurfacePair{ SwapchainRef{}, surfaceRef };
+    return fbid;
   }
+  return -1;
+}
 
-  auto surface = vkFactory->Create(mInstance, mAllocator.get(), mPhysicalDevice);
+SwapchainRef Graphics::CreateSwapchainForSurface( SurfaceRef surface )
+{
+  auto swapchain = Swapchain::New( *this,
+                                   GetGraphicsQueue(0u),
+                                   surface, 2, 0 );
+
+  // store swapchain in the correct pair
+  for( auto&& val : mSurfaceFBIDMap )
+  {
+    if( val.second.surface == surface )
+    {
+      val.second.swapchain = swapchain;
+      break;
+    }
+  }
+
+  return swapchain;
+}
+
+SwapchainRef Graphics::GetSwapchainForSurface( SurfaceRef surface )
+{
+  for( auto&& val : mSurfaceFBIDMap )
+  {
+    if( val.second.surface == surface )
+    {
+      return val.second
+                .swapchain;
+    }
+  }
+  return SwapchainRef();
+}
 
-  // map surface to FBID
-  auto fbid             = ++mBaseFBID;
-  mSurfaceFBIDMap[fbid] = MakeUnique<Surface>(*this, surface, 3u);
-  return fbid;
+SwapchainRef Graphics::GetSwapchainForFBID( FBID surfaceId )
+{
+  if(surfaceId == 0)
+  {
+    return mSurfaceFBIDMap.begin()->second.swapchain;
+  }
+  return mSurfaceFBIDMap[surfaceId].swapchain;
 }
 
 #pragma GCC diagnostic push
@@ -330,7 +372,7 @@ std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
     {
       transferFamily = queueFamilyIndex;
     }
-    if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.get()->GetSurfaceKHR())
+    if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.surface->GetSurfaceKHR())
            .value &&
        presentFamily == -1u)
     {
@@ -489,7 +531,8 @@ Queue& Graphics::GetComputeQueue(uint32_t index) const
 
 Queue& Graphics::GetPresentQueue() const
 {
-  return *mPresentQueue.get();
+  // fixme: should be a dedicated presentation queue
+  return GetGraphicsQueue(0);
 }
 
 Handle< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
@@ -500,15 +543,15 @@ Handle< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInf
   return cmdpool;
 }
 
-Surface& Graphics::GetSurface( FBID surfaceId )
+SurfaceRef Graphics::GetSurface( FBID surfaceId )
 {
   // TODO: FBID == 0 means default framebuffer, but there should be no
   // such thing as default framebuffer.
   if( surfaceId == 0 )
   {
-    return *mSurfaceFBIDMap.begin()->second.get();
+    return mSurfaceFBIDMap.begin()->second.surface;
   }
-  return *mSurfaceFBIDMap[surfaceId].get();
+  return mSurfaceFBIDMap[surfaceId].surface;
 }
 
 // TODO: all this stuff should go into some vulkan cache
@@ -587,7 +630,7 @@ void Graphics::RemoveDescriptorPool( std::unique_ptr<DescriptorPool> pool )
   NotImplemented();
 }
 
-Handle<Shader> Graphics::FindShader( vk::ShaderModule shaderModule )
+ShaderRef Graphics::FindShader( vk::ShaderModule shaderModule )
 {
   for( auto&& iter : mShaderCache )
   {
@@ -599,6 +642,19 @@ Handle<Shader> Graphics::FindShader( vk::ShaderModule shaderModule )
   return Handle<Shader>();
 }
 
+ImageRef Graphics::FindImage( vk::Image image )
+{
+  for( auto&& iter : mImageCache )
+  {
+    if( iter->GetVkImage() == image )
+    {
+      return ImageRef(&*iter);
+    }
+  }
+  return ImageRef();
+}
+
+
 
 } // namespace Vulkan
 } // namespace Graphics
index 8d4fafa..7230b58 100644 (file)
@@ -25,7 +25,7 @@
 // INTERNAL INCLUDES
 #include <dali/graphics/vulkan/vulkan-types.h>
 #include <dali/integration-api/graphics/surface-factory.h>
-
+#include <dali/graphics/vulkan/vulkan-swapchain.h>
 namespace Dali
 {
 namespace Graphics
@@ -58,6 +58,12 @@ class DescriptorPool;
 class GpuMemoryManager;
 class Controller;
 
+struct SwapchainSurfacePair
+{
+  SwapchainRef swapchain;
+  SurfaceRef surface;
+};
+
 class Graphics
 {
 
@@ -73,7 +79,13 @@ public:
   // new way
   FBID CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory);
 
-  Surface& GetSurface( FBID surfaceId );
+  SwapchainRef CreateSwapchainForSurface( SurfaceRef surface );
+
+  SurfaceRef GetSurface( FBID surfaceId );
+
+  SwapchainRef GetSwapchainForSurface( SurfaceRef surface );
+
+  SwapchainRef GetSwapchainForFBID( FBID surfaceId );
 
   void CreateDevice();
 
@@ -138,29 +150,30 @@ private:
   // queue family properties
   std::vector< vk::QueueFamilyProperties > mQueueFamilyProperties;
 
-  std::unordered_map< FBID, UniqueSurface > mSurfaceFBIDMap;
+  std::unordered_map< FBID, SwapchainSurfacePair > mSurfaceFBIDMap;
   FBID mBaseFBID{0u};
 
   // Sets of queues
   std::vector< std::unique_ptr<Queue> >  mGraphicsQueues;
   std::vector< std::unique_ptr<Queue> >  mTransferQueues;
   std::vector< std::unique_ptr<Queue> >  mComputeQueues;
-  std::unique_ptr< Queue > mPresentQueue;
+  //std::unique_ptr< Queue > mPresentQueue;
 
   Platform                               mPlatform  { Platform::UNDEFINED };
 
 public:
   // TODO: all this stuff should go into some vulkan cache
 
-  void AddBuffer( Handle<Buffer> buffer );
-  void AddImage( Handle<Image> image );
-  void AddPipeline( Handle<Pipeline> pipeline );
-  void AddShader( Handle<Shader> shader );
-  void AddCommandPool( Handle<CommandPool> pool );
-  void AddDescriptorPool( Handle<DescriptorPool> pool );
-  void AddFramebuffer( Handle<Framebuffer> framebuffer );
+  void AddBuffer( BufferRef buffer );
+  void AddImage( ImageRef image );
+  void AddPipeline( PipelineRef pipeline );
+  void AddShader( ShaderRef shader );
+  void AddCommandPool( CommandPoolRef pool );
+  void AddDescriptorPool( DescriptorPoolRef pool );
+  void AddFramebuffer( FramebufferRef framebuffer );
 
   ShaderRef FindShader( vk::ShaderModule shaderModule );
+  ImageRef FindImage( vk::Image image );
 
   void RemoveBuffer( Buffer& buffer );
   void RemoveShader( Shader& shader );
index 99aa995..0c4d9c4 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <dali/graphics/vulkan/vulkan-graphics.h>
 #include <dali/graphics/vulkan/vulkan-image.h>
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
 
 namespace Dali
 {
@@ -56,12 +57,19 @@ struct Image::Impl
     return true;
   }
 
+  void BindMemory( const GpuMemoryBlockRef& handle )
+  {
+    mGraphics.GetDevice().bindImageMemory( mVkImage, *handle, 0 );
+    mDeviceMemory = handle;
+  }
+
   Image&              mOwner;
   Graphics&           mGraphics;
   vk::Image           mVkImage;
   vk::ImageLayout     mVkImageLayout;
   vk::ImageCreateInfo mCreateInfo;
 
+  GpuMemoryBlockRef   mDeviceMemory;
   bool mIsExternal;
 };
 
@@ -145,8 +153,14 @@ vk::ImageTiling Image::GetVkImageTiling() const
   return mImpl->mCreateInfo.tiling;
 }
 
-void Image::BindMemory( GpuMemoryBlockRef& handle )
+void Image::BindMemory( const GpuMemoryBlockRef& handle )
+{
+  mImpl->BindMemory( handle );
+}
+
+vk::ImageUsageFlags Image::GetVkImageUsageFlags() const
 {
+  return mImpl->mCreateInfo.usage;
 }
 
 /***************************************************************************
@@ -187,29 +201,58 @@ struct ImageView::Impl
 ImageViewRef ImageView::New( Graphics& graphics, ImageRef image, vk::ImageViewCreateInfo info )
 {
   auto retval = ImageViewRef( new ImageView( graphics, image, info ) );
-  if(!retval->mImpl->Initialise())
+  if( !retval->mImpl->Initialise() )
   {
     return ImageViewRef();
   }
   return retval;
 }
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
 ImageViewRef ImageView::New( Graphics& graphics, ImageRef image )
 {
-  // create reference, image may be null
-  auto retval = ImageViewRef( new ImageView( graphics, image, vk::ImageViewCreateInfo{} ) );
-  if(image)
+  vk::ImageAspectFlags aspectFlags{};
+  if( image->GetVkImageUsageFlags() & vk::ImageUsageFlagBits::eColorAttachment )
   {
+    aspectFlags |= vk::ImageAspectFlagBits::eColor;
+  }
+  if( image->GetVkImageUsageFlags() & vk::ImageUsageFlagBits::eDepthStencilAttachment )
+  {
+    aspectFlags |= (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil);
+  }
+
+  auto subresourceRange = vk::ImageSubresourceRange{}
+    .setAspectMask( aspectFlags )
+    .setBaseArrayLayer( 0 )
+    .setBaseMipLevel( 0 )
+    .setLevelCount( image->GetLevelCount() )
+    .setLayerCount( image->GetLayerCount() );
 
+  // create reference, image may be null
+  auto retval = ImageViewRef( new ImageView( graphics,
+                                             image,
+                                             vk::ImageViewCreateInfo{}
+                                               .setViewType( vk::ImageViewType::e2D )
+                                               .setFormat( image->GetVkFormat() )
+                                               .setSubresourceRange(subresourceRange)
+                                               .setComponents( { vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB,vk::ComponentSwizzle::eA } )
+                                                .setImage( image->GetVkImage() )));
+  if(!retval->mImpl->Initialise())
+  {
+    return ImageViewRef();
   }
+
   return retval;
 }
+#pragma GCC diagnostic pop
 
 ImageView::ImageView( Graphics& graphics, ImageRef image, const VkImageViewCreateInfo& createInfo )
 {
   mImpl = MakeUnique<Impl>( *this, graphics, image, createInfo );
 }
 
+
 ImageView::~ImageView() = default;
 
 const vk::ImageView& ImageView::GetVkImageView() const
index deb574c..7d081bf 100644 (file)
@@ -27,6 +27,7 @@ namespace Graphics
 namespace Vulkan
 {
 class ImageView;
+using InternalVkImage = vk::Image;
 class Image : public VkManaged
 {
 public:
@@ -108,10 +109,16 @@ public:
   vk::ImageTiling GetVkImageTiling() const;
 
   /**
+   *
+   * @return
+   */
+  vk::ImageUsageFlags  GetVkImageUsageFlags() const;
+
+  /**
    * Binds image memory
    * @param handle
    */
-  void BindMemory( GpuMemoryBlockRef& handle );
+  void BindMemory( const GpuMemoryBlockRef& handle );
 
   /**
    * Creates new VkImage with given specification, it doesn't
@@ -121,6 +128,11 @@ public:
    */
   Image( Graphics& graphics, const vk::ImageCreateInfo& createInfo, vk::Image externalImage );
 
+  operator InternalVkImage() const
+  {
+    return GetVkImage();
+  }
+
 private:
   class Impl;
   std::unique_ptr<Impl> mImpl;
index 00971b3..00b0bbd 100644 (file)
@@ -18,6 +18,7 @@
 #include <dali/graphics/vulkan/vulkan-pipeline.h>
 #include <dali/graphics/vulkan/vulkan-graphics.h>
 #include <dali/graphics/vulkan/vulkan-surface.h>
+#include <dali/graphics/vulkan/vulkan-framebuffer.h>
 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
 #include <dali/graphics/vulkan/spirv/vulkan-spirv.h>
 
@@ -83,7 +84,8 @@ struct Pipeline::Impl
     // in place of swapchain structures!
     if( !mInfo.renderPass )
     {
-      SetRenderPass( mGraphics.GetSurface( 0 ).GetRenderPass() );
+      SetRenderPass( mGraphics.GetSwapchainForFBID(0u)->
+                                GetCurrentFramebuffer()->GetVkRenderPass());
     }
 
     SetRasterizationState();
index fa7417b..6af405a 100644 (file)
@@ -123,7 +123,7 @@ std::unique_ptr< Submission > Queue::Submit(const std::vector< CommandBufferRef
   info.setPWaitSemaphores(semaphores.waitSemaphores.data());
   info.setPWaitDstStageMask(semaphores.waitDstStageMasks.data());
 
-  VkAssert(mQueue.submit(1, &info, fence->GetFence()));
+  VkAssert(mQueue.submit(1, &info, fence ? fence->GetFence() : nullptr ));
 
   return MakeUnique< Submission >(fence);
 }
index f87ec77..e116bbb 100644 (file)
@@ -231,15 +231,15 @@ std::unique_ptr<Test::xcb_window_t> create_xcb_window( int width, int height )
 namespace VulkanTest
 {
 Dali::Graphics::Vulkan::GpuMemoryBlockRef test_gpu_memory_manager(
-  Dali::Graphics::Vulkan::Graphics&             graphics,
-  GpuMemoryManager&                             gpuManager,
-  const Dali::Graphics::Vulkan::Handle<Buffer>& buffer )
+  Dali::Graphics::Vulkan::Graphics &graphics,
+  GpuMemoryManager &gpuManager,
+  const Dali::Graphics::Vulkan::Handle<Buffer> &buffer)
 {
-  auto  device    = graphics.GetDevice();
-  autoallocator = graphics.GetAllocator();
+  auto device = graphics.GetDevice();
+  auto &allocator = graphics.GetAllocator();
 
-  autogpuAllocator = gpuManager.GetDefaultAllocator();
-  return gpuAllocator.Allocate( buffer, vk::MemoryPropertyFlagBits::eHostVisible );
+  auto &gpuAllocator = gpuManager.GetDefaultAllocator();
+  return gpuAllocator.Allocate(buffer, vk::MemoryPropertyFlagBits::eHostVisible);
 }
 
 struct UniformData
@@ -247,24 +247,26 @@ struct UniformData
   mat4 mvp;
   vec4 color;
   vec3 size;
-} __attribute__( ( aligned( 16 ) ) );
+} __attribute__(( aligned( 16 )));
 
 struct UniformClipData
 {
   mat4 clip;
-} __attribute__( ( aligned( 16 ) ) );
+} __attribute__(( aligned( 16 )));
 
 mat4 MVP;
 
 template<class T>
-void update_buffer( Dali::Graphics::Vulkan::BufferRef buffer, T& value )
+void update_buffer(Dali::Graphics::Vulkan::BufferRef buffer, T &value)
 {
-  auto ptr = reinterpret_cast<T*>( buffer->GetMemoryHandle()->Map() );
-  *ptr     = value;
-  buffer->GetMemoryHandle()->Unmap();
+  auto ptr = reinterpret_cast<T *>( buffer->GetMemoryHandle()
+                                          ->Map());
+  *ptr = value;
+  buffer->GetMemoryHandle()
+        ->Unmap();
 }
 
-void update_translation( Dali::Graphics::Vulkan::BufferRef buffer )
+void update_translation(Dali::Graphics::Vulkan::BufferRef buffer)
 {
   static float x = 0.0f;
   x += 0.5f;
@@ -279,100 +281,107 @@ void update_translation( Dali::Graphics::Vulkan::BufferRef buffer )
            lookAt( vec3( 0.0f, 0.0f, 10.0f ), vec3( 0.0f, 0.0f, 0.0f ), vec3( 0.0f, 1.0f, 0.0f ) ) * modelMat;
 
   update_buffer( buffer, ub );
-   */
+  */
 }
 
-Dali::Graphics::Vulkan::BufferRef create_uniform_buffer( Dali::Graphics::Vulkan::Graphics& gr )
+Dali::Graphics::Vulkan::BufferRef create_uniform_buffer(Dali::Graphics::Vulkan::Graphics &gr)
 {
   // create uniform buffer
-  auto uniformBuffer = Buffer::New( gr, sizeof( UniformData ), Buffer::Type::UNIFORM );
+  auto uniformBuffer = Buffer::New(gr, sizeof(UniformData), Buffer::Type::UNIFORM);
 
   // allocate memory
-  auto memory = gr.GetDeviceMemoryManager().GetDefaultAllocator().Allocate( uniformBuffer,
-                                                                            vk::MemoryPropertyFlagBits::eHostVisible );
+  auto memory = gr.GetDeviceMemoryManager()
+                  .GetDefaultAllocator()
+                  .Allocate(uniformBuffer,
+                            vk::MemoryPropertyFlagBits::eHostVisible);
 
   // bind memory
-  uniformBuffer->BindMemory( memory );
+  uniformBuffer->BindMemory(memory);
 
-  auto ub = reinterpret_cast<UniformData*>( memory->Map() );
+  auto ub = reinterpret_cast<UniformData *>( memory->Map());
 
-  ub->mvp = mat4{1.0f} * ortho( 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 100.0f ) *
-            lookAt( vec3( 0.0f, 0.0f, 10.0f ), vec3( 0.0f, 0.0f, 0.0f ), vec3( 0.0f, 1.0f, 0.0f ) );
-  ub->color = vec4( 0.0f, 1.0f, 1.0f, 1.0f );
-  ub->size  = vec3( 1.0f, 1.0f, 1.0f );
+  ub->mvp   = mat4{1.0f} * ortho(0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 100.0f) *
+              lookAt(vec3(0.0f, 0.0f, 10.0f), vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
+  ub->color = vec4(0.0f, 1.0f, 1.0f, 1.0f);
+  ub->size  = vec3(1.0f, 1.0f, 1.0f);
 
   memory->Unmap();
 
   return uniformBuffer;
 }
 
-Dali::Graphics::Vulkan::BufferRef create_clip_buffer( Dali::Graphics::Vulkan::Graphics& gr )
+Dali::Graphics::Vulkan::BufferRef create_clip_buffer(Dali::Graphics::Vulkan::Graphics &gr)
 {
   const glm::mat4 clip(
-    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 );
+    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);
 
   // create uniform buffer
-  auto uniformBuffer = Buffer::New( gr, sizeof( UniformClipData ), Buffer::Type::UNIFORM );
+  auto uniformBuffer = Buffer::New(gr, sizeof(UniformClipData), Buffer::Type::UNIFORM);
 
   // allocate memory
-  auto memory = gr.GetDeviceMemoryManager().GetDefaultAllocator().Allocate( uniformBuffer,
-                                                                            vk::MemoryPropertyFlagBits::eHostVisible );
+  auto memory = gr.GetDeviceMemoryManager()
+                  .GetDefaultAllocator()
+                  .Allocate(uniformBuffer,
+                            vk::MemoryPropertyFlagBits::eHostVisible);
   // bind memory
-  uniformBuffer->BindMemory( memory );
+  uniformBuffer->BindMemory(memory);
   auto dst = memory->MapTyped<mat4>();
-  std::copy( &clip, &clip + 1, dst );
+  std::copy(&clip, &clip + 1, dst);
   memory->Unmap();
   return uniformBuffer;
 }
 
-Dali::Graphics::Vulkan::Handle<DescriptorPool> create_descriptor_pool( Dali::Graphics::Vulkan::Graphics& gr )
+Dali::Graphics::Vulkan::Handle<DescriptorPool> create_descriptor_pool(Dali::Graphics::Vulkan::Graphics &gr)
 {
   vk::DescriptorPoolSize size;
-  size.setDescriptorCount( 1024 ).setType( vk::DescriptorType::eUniformBuffer );
+  size.setDescriptorCount(1024)
+      .setType(vk::DescriptorType::eUniformBuffer);
 
   // TODO: how to organize this???
   auto pool = DescriptorPool::New(
-    gr, vk::DescriptorPoolCreateInfo{}.setMaxSets( 1024 ).setPoolSizeCount( 1 ).setPPoolSizes( &size ) );
+    gr, vk::DescriptorPoolCreateInfo{}.setMaxSets(1024)
+                                      .setPoolSizeCount(1)
+                                      .setPPoolSizes(&size));
   return pool;
 }
 
-void test_framebuffer( Dali::Graphics::Vulkan::Graphics& graphics )
+void test_framebuffer(Dali::Graphics::Vulkan::Graphics &graphics)
 {
   using namespace Dali::Graphics::Vulkan;
   // framebuffer
-  auto fb = NewRef<Framebuffer>( graphics, 640, 480 );
+  auto fb = NewRef<Framebuffer>(graphics, 640, 480);
 
   // attachment
-  auto image = NewRef<Image>( graphics,
-                              vk::ImageCreateInfo{}
-                                .setFormat( vk::Format::eR32G32B32A32Sfloat )
-                                .setTiling( vk::ImageTiling::eOptimal )
-                                .setMipLevels( 1 )
-                                .setImageType( vk::ImageType::e2D )
-                                .setExtent( vk::Extent3D( 640, 480, 1 ) )
-                                .setArrayLayers( 1 )
-                                .setUsage( vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eColorAttachment )
-                                .setSharingMode( vk::SharingMode::eExclusive )
-                                .setInitialLayout( vk::ImageLayout::eUndefined )
-                                .setSamples( vk::SampleCountFlagBits::e1 ) );
+  auto image = NewRef<Image>(graphics,
+                             vk::ImageCreateInfo{}
+                               .setFormat(vk::Format::eR32G32B32A32Sfloat)
+                               .setTiling(vk::ImageTiling::eOptimal)
+                               .setMipLevels(1)
+                               .setImageType(vk::ImageType::e2D)
+                               .setExtent(vk::Extent3D(640, 480, 1))
+                               .setArrayLayers(1)
+                               .setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eColorAttachment)
+                               .setSharingMode(vk::SharingMode::eExclusive)
+                               .setInitialLayout(vk::ImageLayout::eUndefined)
+                               .setSamples(vk::SampleCountFlagBits::e1));
 
   auto imageView = NewRef<ImageView>(
     graphics,
     image,
     vk::ImageViewCreateInfo{}
-      .setFormat( vk::Format::eR32G32B32A32Sfloat )
-      .setComponents( vk::ComponentMapping(
-        vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB, vk::ComponentSwizzle::eA ) )
-      .setImage( image->GetVkImage() )
-      .setSubresourceRange( vk::ImageSubresourceRange{}
-                              .setLayerCount( 1 )
-                              .setLevelCount( 1 )
-                              .setBaseMipLevel( 0 )
-                              .setBaseArrayLayer( 0 )
-                              .setAspectMask( vk::ImageAspectFlagBits::eColor ) )
-      .setViewType( vk::ImageViewType::e2D ) );
-
-  fb->SetAttachment( imageView, Framebuffer::AttachmentType::COLOR, 0u );
+      .setFormat(vk::Format::eR32G32B32A32Sfloat)
+      .setComponents(vk::ComponentMapping(
+        vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB, vk::ComponentSwizzle::eA))
+      .setImage(image->GetVkImage())
+      .setSubresourceRange(vk::ImageSubresourceRange{}
+                             .setLayerCount(1)
+                             .setLevelCount(1)
+                             .setBaseMipLevel(0)
+                             .setBaseArrayLayer(0)
+                             .setAspectMask(vk::ImageAspectFlagBits::eColor))
+      .setViewType(vk::ImageViewType::e2D));
+
+  fb->SetAttachment(imageView, Framebuffer::AttachmentType::COLOR, 0u);
 
   //fb->GetRenderPass();
 
@@ -389,137 +398,171 @@ void test_handle()
   handle.GetRefCount();*/
 }
 
-PipelineRef create_pipeline( Dali::Graphics::Vulkan::Graphics& graphics,
-                             Dali::Graphics::Vulkan::ShaderRef vertexShader,
-                             Dali::Graphics::Vulkan::ShaderRef fragmentShader )
+PipelineRef create_pipeline(Dali::Graphics::Vulkan::Graphics &graphics,
+                            Dali::Graphics::Vulkan::ShaderRef vertexShader,
+                            Dali::Graphics::Vulkan::ShaderRef fragmentShader)
 {
   using namespace Dali::Graphics::Vulkan;
   auto pipelineInfo = vk::GraphicsPipelineCreateInfo{};
-  auto pipeline     = Pipeline::New( graphics, pipelineInfo );
+  auto pipeline     = Pipeline::New(graphics, pipelineInfo);
 
-  pipeline->SetShader( vertexShader, Shader::Type::VERTEX );
-  pipeline->SetShader( fragmentShader, Shader::Type::FRAGMENT );
-  pipeline->SetViewport( 0, 0, 640, 480 );
+  pipeline->SetShader(vertexShader, Shader::Type::VERTEX);
+  pipeline->SetShader(fragmentShader, Shader::Type::FRAGMENT);
+  pipeline->SetViewport(0, 0, 640, 480);
   pipeline->SetVertexInputState(
     std::vector<vk::VertexInputAttributeDescription>{
-      vk::VertexInputAttributeDescription{}.setBinding( 0 ).setOffset( 0 ).setLocation( 0 ).setFormat(
-        vk::Format::eR32G32B32Sfloat )},
+      vk::VertexInputAttributeDescription{}.setBinding(0)
+                                           .setOffset(0)
+                                           .setLocation(0)
+                                           .setFormat(
+                                             vk::Format::eR32G32B32Sfloat)},
     std::vector<vk::VertexInputBindingDescription>{vk::VertexInputBindingDescription{}
-                                                     .setBinding( 0 )
-                                                     .setStride( sizeof( float ) * 3 )
-                                                     .setInputRate( vk::VertexInputRate::eVertex )} );
-  pipeline->SetInputAssemblyState( vk::PrimitiveTopology::eTriangleList, false );
+      .setBinding(0)
+      .setStride(sizeof(float) * 3)
+      .setInputRate(vk::VertexInputRate::eVertex)});
+  pipeline->SetInputAssemblyState(vk::PrimitiveTopology::eTriangleList, false);
 
-  if( !pipeline->Compile() )
+  if (!pipeline->Compile())
   {
     pipeline.Reset();
   }
   return pipeline;
 }
 
+int TextureTestMain( Dali::Graphics::Vulkan::Graphics& );
+
+int RunTestMain2()
+{
+#if USE_XLIB == 1
+  auto window         = Test::create_xlib_window( 640, 480 );
+  auto surfaceFactory = std::unique_ptr<VkSurfaceXlib>{new VkSurfaceXlib{window->display, window->window}};
+#else
+  auto window         = Test::create_xcb_window(640, 480);
+  auto surfaceFactory = std::unique_ptr<VkSurfaceXcb>{new VkSurfaceXcb{window->connection, window->window}};
+#endif
+
+  auto graphics = MakeUnique<Graphics>();
+  auto fbid     = graphics->Create(std::move(surfaceFactory));
+
+  // access internal implementation
+  auto &gr = graphics->GetImplementation<Dali::Graphics::Vulkan::Graphics>();
+
+  // GPU memory manager
+  auto &memmgr = gr.GetDeviceMemoryManager();
+
+  return TextureTestMain( gr );
+}
+
 int RunTestMain()
 {
 #if USE_XLIB == 1
   auto window         = Test::create_xlib_window( 640, 480 );
   auto surfaceFactory = std::unique_ptr<VkSurfaceXlib>{new VkSurfaceXlib{window->display, window->window}};
 #else
-  auto window         = Test::create_xcb_window( 640, 480 );
+  auto window         = Test::create_xcb_window(640, 480);
   auto surfaceFactory = std::unique_ptr<VkSurfaceXcb>{new VkSurfaceXcb{window->connection, window->window}};
 #endif
 
   auto graphics = MakeUnique<Graphics>();
-  auto fbid     = graphics->Create( std::move( surfaceFactory ) );
+  auto fbid     = graphics->Create(std::move(surfaceFactory));
 
   // access internal implementation
-  autogr = graphics->GetImplementation<Dali::Graphics::Vulkan::Graphics>();
+  auto &gr = graphics->GetImplementation<Dali::Graphics::Vulkan::Graphics>();
 
   // GPU memory manager
-  automemmgr = gr.GetDeviceMemoryManager();
+  auto &memmgr = gr.GetDeviceMemoryManager();
 
   const vec3 VERTICES[] = {
-    {0.0f, 0.0f, 0.0f},
-    {320.0f, 0.0f, 0.0f},
-    {0.0f, 160.0f, 0.0f},
+    {0.0f,   0.0f,   0.0f},
+    {320.0f, 0.0f,   0.0f},
+    {0.0f,   160.0f, 0.0f},
   };
 
   // shaders
-  auto vertexShader = Shader::New( gr, VSH_CODE.data(), VSH_CODE.size() );
+  auto vertexShader = Shader::New(gr, VSH_CODE.data(), VSH_CODE.size());
 
-  auto fragmentShader = Shader::New( gr, FSH_CODE.data(), FSH_CODE.size() );
+  auto fragmentShader = Shader::New(gr, FSH_CODE.data(), FSH_CODE.size());
 
   // buffer
-  auto vertexBuffer = Buffer::New( gr, sizeof( float ) * 3 * 3, Buffer::Type::VERTEX );
+  auto vertexBuffer = Buffer::New(gr, sizeof(float) * 3 * 3, Buffer::Type::VERTEX);
 
-  auto descriptorPool = create_descriptor_pool( gr );
+  auto descriptorPool = create_descriptor_pool(gr);
 
-  autogpuManager = gr.GetDeviceMemoryManager();
+  auto &gpuManager = gr.GetDeviceMemoryManager();
 
-  auto bufferMemory = test_gpu_memory_manager( gr, gpuManager, vertexBuffer );
-  vertexBuffer->BindMemory( bufferMemory );
+  auto bufferMemory = test_gpu_memory_manager(gr, gpuManager, vertexBuffer);
+  vertexBuffer->BindMemory(bufferMemory);
 
-  auto ptr = static_cast<uint8_t*>( bufferMemory->Map() );
-  std::copy( reinterpret_cast<const uint8_t*>( VERTICES ),
-             reinterpret_cast<const uint8_t*>( VERTICES ) + ( sizeof( float ) * 9 ),
-             ptr );
+  auto ptr = static_cast<uint8_t *>( bufferMemory->Map());
+  std::copy(reinterpret_cast<const uint8_t *>( VERTICES ),
+            reinterpret_cast<const uint8_t *>( VERTICES ) + (sizeof(float) * 9),
+            ptr);
   bufferMemory->Unmap();
 
-  auto pipeline = create_pipeline( gr, vertexShader, fragmentShader );
+  auto pipeline = create_pipeline(gr, vertexShader, fragmentShader);
 
   auto descriptorSet = descriptorPool->AllocateDescriptorSets(
     vk::DescriptorSetAllocateInfo{}
-      .setPSetLayouts( pipeline->GetVkDescriptorSetLayouts().data() )
-      .setDescriptorSetCount( pipeline->GetVkDescriptorSetLayouts().size() ) );
+      .setPSetLayouts(pipeline->GetVkDescriptorSetLayouts()
+                              .data())
+      .setDescriptorSetCount(pipeline->GetVkDescriptorSetLayouts()
+                                     .size()));
 
 
-  auto commandPool = CommandPool::New( gr );
+  auto commandPool = CommandPool::New(gr);
 
-  auto uniformBuffer = create_uniform_buffer( gr );
+  auto uniformBuffer = create_uniform_buffer(gr);
 
-  auto clipBuffer = create_clip_buffer( gr );
+  auto clipBuffer = create_clip_buffer(gr);
 
-  descriptorSet[0]->WriteUniformBuffer( 0, uniformBuffer, 0, uniformBuffer->GetSize() );
-  descriptorSet[0]->WriteUniformBuffer( 1, clipBuffer, 0, clipBuffer->GetSize() );
+  descriptorSet[0]->WriteUniformBuffer(0, uniformBuffer, 0, uniformBuffer->GetSize());
+  descriptorSet[0]->WriteUniformBuffer(1, clipBuffer, 0, clipBuffer->GetSize());
 
   // get new buffer
-  auto cmdDraw = commandPool->NewCommandBuffer( false );
+  auto cmdDraw = commandPool->NewCommandBuffer(false);
 
   // begin recording
-  cmdDraw->Begin( vk::CommandBufferUsageFlagBits::eRenderPassContinue );
+  cmdDraw->Begin(vk::CommandBufferUsageFlagBits::eRenderPassContinue);
 
   // vertex buffer
-  cmdDraw->BindVertexBuffer( 0, vertexBuffer, 0 );
+  cmdDraw->BindVertexBuffer(0, vertexBuffer, 0);
 
   // pipeline
-  cmdDraw->BindGraphicsPipeline( pipeline );
+  cmdDraw->BindGraphicsPipeline(pipeline);
 
   // descriptor sets
-  cmdDraw->BindDescriptorSets( descriptorSet, 0 );
+  cmdDraw->BindDescriptorSets(descriptorSet, 0);
 
   // do draw
-  cmdDraw->Draw( 3, 1, 0, 0 );
+  cmdDraw->Draw(3, 1, 0, 0);
 
   // finish
   cmdDraw->End();
 
   bool running = true;
 
-  while( running )
+  while (running)
   {
-    graphics->PreRender( fbid );
+    graphics->PreRender(fbid);
     // queue submit draw
 
-    auto cmdbuf = gr.GetSurface( fbid ).GetCurrentCommandBuffer();
+    auto cmdbuf = gr.GetSwapchainForFBID(fbid)
+                    ->GetPrimaryCommandBuffer();
 
     // get command buffer for current frame and execute the draw call
-    cmdbuf->ExecuteCommands( {cmdDraw} );
+    cmdbuf->ExecuteCommands({cmdDraw});
 
-    graphics->PostRender( fbid );
+    graphics->PostRender(fbid);
 
-    update_translation( uniformBuffer );
+    update_translation(uniformBuffer);
   }
   return 0;
 }
 
+void texture_test(void *data, size_t size)
+{
+
+}
 
 using namespace Dali::Graphics::Vulkan::SpirV;
 void spirv_test0( std::vector<SPIRVWord> code )
@@ -543,11 +586,12 @@ void RunSPIRVTest()
 }
 
 
+
 } // namespace VulkanTest
 
 int main()
 {
-  VulkanTest::RunTestMain();
+  VulkanTest::RunTestMain2();
 
   //VulkanTest::RunSPIRVTest();
 }
index a0a9d7a..4f7d310 100644 (file)
  */
 
 // INTERNAL INCLUDES
-#include <dali/graphics/vulkan/vulkan-command-buffer.h>
-#include <dali/graphics/vulkan/vulkan-command-pool.h>
-#include <dali/graphics/vulkan/vulkan-fence.h>
-#include <dali/graphics/vulkan/vulkan-graphics.h>
-#include <dali/graphics/vulkan/vulkan-queue.h>
 #include <dali/graphics/vulkan/vulkan-surface.h>
-#include <dali/graphics/vulkan/vulkan-image.h>
+#include <dali/graphics/vulkan/vulkan-graphics.h>
+#include <dali/integration-api/graphics/vulkan/vk-surface-factory.h>
 
 namespace Dali
 {
@@ -31,460 +27,83 @@ namespace Graphics
 namespace Vulkan
 {
 
-namespace
-{
-// constants
-auto VK_COMPONENT_MAPPING_RGBA = vk::ComponentMapping{}
-                                     .setR(vk::ComponentSwizzle::eR)
-                                     .setG(vk::ComponentSwizzle::eG)
-                                     .setB(vk::ComponentSwizzle::eB)
-                                     .setA(vk::ComponentSwizzle::eA);
-}
-
-SwapchainImage::SwapchainImage()  = default;
-SwapchainImage::~SwapchainImage() = default;
-
-Surface::Surface(Graphics& graphics, vk::SurfaceKHR surface, uint32_t bufferCount, bool hasDepthStencil)
-: mGraphics(graphics), mSurface(surface), mSwapchain{nullptr}, mBufferCount{bufferCount}, mHasDepthStencil(hasDepthStencil)
-{
-}
-
-Surface::~Surface()
+struct Surface::Impl
 {
-  if(mSwapchain)
+  Impl( Surface& owner, Graphics& graphics, std::unique_ptr<SurfaceFactory> surfaceFactory ) :
+  mOwner( owner ), mGraphics( graphics ), mSurfaceFactory( std::move(surfaceFactory) )
   {
-    DestroySwapchain();
+    mVulkanSurfaceFactory = dynamic_cast<Dali::Integration::Graphics::Vulkan::VkSurfaceFactory*>(mSurfaceFactory.get());
   }
-  if(mSurface)
-  {
-    mGraphics.GetInstance().destroySurfaceKHR(mSurface, mGraphics.GetAllocator());
-  }
-}
 
-void Surface::AcquireNextImage()
-{
-  // if swapchain hasn't been created yet, create it
-  // TODO: deferring may bring a lag when surface is swapped very first time
-  // it might be good to have an option to create swapchain regardless further usage
-  if(!mSwapchain)
+  ~Impl()
   {
-    CreateSwapchain();
-  }
 
-  if(!mFrameFence)
-  {
-    mFrameFence = Fence::New(mGraphics);
   }
 
-  // acquire image, for simplicity using fence for acquiring as it is unknown what next command buffer will
-  // be executed yet
-  mFrameFence->Reset();
-  uint32_t index = VkAssert(mGraphics.GetDevice().acquireNextImageKHR(mSwapchain, 1000000, nullptr,
-                                                                      mFrameFence->GetFence()));
-  mFrameFence->Wait();
-  mFrameFence->Reset();
-
-  mCurrentBufferIndex = index;
-
-  auto& swapImage = mSwapImages[index];
-
-  // change layout if necessary to color attachment
-  if(swapImage.layout != vk::ImageLayout::eColorAttachmentOptimal)
+  bool Initialise()
   {
-    auto& queue = mGraphics.GetGraphicsQueue();
-    queue.Submit(swapImage.layoutToColorCmdBuf, mFrameFence)->WaitForFence();
-  }
-
-  mFrameFence->Reset();
-
-  // todo: anything to be done before beginning main command buffer?
-  BeginRenderPass();
-}
-
-void Surface::BeginRenderPass()
-{
-  auto& swapImage = mSwapImages[mCurrentBufferIndex];
-
-  // begin command buffer ( can be directly obtained through Graphics( surface )
-  swapImage.mainCmdBuf->Begin(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
-
-  /*
-   * todo: automatically start main render pass -> this may have to be done manually in future
-   * if more flexibility is needed
-   */
-  auto vkCmdBuf = swapImage.mainCmdBuf->GetVkCommandBuffer();
-  {
-    std::array< vk::ClearValue, 2 > clearValues;
-
-    static float r = 1.0f;
-    //r += 0.01f;
-    if(r > 1.0f)
-      r -= 1.0f;
-
-    clearValues[0].color.setFloat32({0.0f, 0.0f, 0.0f, 1.0f});
-    clearValues[1].depthStencil.setDepth(1.0f).setStencil(0.0f);
-
-    auto rpInfo = vk::RenderPassBeginInfo{};
-    rpInfo.setRenderPass(mDefaultRenderPass)
-        .setFramebuffer(swapImage.framebuffer)
-        .setRenderArea(vk::Rect2D{}.setOffset({0, 0}).setExtent(mExtent))
-        .setClearValueCount(mHasDepthStencil ? 2 : 1)
-        .setPClearValues(clearValues.data());
-
-    auto subpassContents = vk::SubpassContents{vk::SubpassContents::eSecondaryCommandBuffers};
-    vkCmdBuf.beginRenderPass(rpInfo, subpassContents);
-  }
-}
-
-std::vector<vk::ClearValue> Surface::GetClearValues() const
-{
-  static float r = 0.0f;
-  r += 0.01f;
-  if(r > 1.0f)
-    r -= 1.0f;
-
-  std::array< vk::ClearValue, 2 > clearValues;
-  clearValues[0].color.setFloat32({r, 0.0f, 0.0f, 1.0f});
-  clearValues[1].depthStencil.setDepth(1.0f).setStencil(0.0f);
-
-  auto retval = std::vector<vk::ClearValue>{};
-  retval.emplace_back( clearValues[0] );
-  if( mHasDepthStencil )
-  {
-    retval.emplace_back( clearValues[1] );
-  }
-  return retval;
-}
-
-vk::Extent2D Surface::GetSize() const
-{
-  return mCapabilities->currentExtent;
-}
-
-Handle<CommandBuffer> Surface::GetCommandBuffer( uint32_t index )
-{
-  return mSwapImages[index].mainCmdBuf;
-}
-
-Handle<CommandBuffer> Surface::GetCurrentCommandBuffer()
-{
-  return mSwapImages[mCurrentBufferIndex].mainCmdBuf;
-}
-
-void Surface::EndRenderPass()
-{
-  // todo: use semaphores and do not create fences all over again
-  auto& swapImage = mSwapImages[mCurrentBufferIndex];
-  auto  vkCmdBuf  = swapImage.mainCmdBuf->GetVkCommandBuffer();
-
-  // complete render pass
-  vkCmdBuf.endRenderPass();
-
-  // finalize command buffer
-  swapImage.mainCmdBuf->End();
-
-  // submit
-  auto& queue = mGraphics.GetGraphicsQueue();
-  queue.Submit(swapImage.mainCmdBuf, mFrameFence)->WaitForFence();
-}
-
-void Surface::Present()
-{
-  // complete render pass and command buffer
-  EndRenderPass();
-
-  auto& swapImage = mSwapImages[mCurrentBufferIndex];
-  auto  result    = mGraphics.GetGraphicsQueue().Present(mSwapchain, mCurrentBufferIndex);
-  if(result != vk::Result::eSuccess)
-  {
-    //todo: handle swapchain invalidation
-  }
-  swapImage.layout = vk::ImageLayout::ePresentSrcKHR;
-  // todo: test result against swapchain expiration
-}
-
-void Surface::CreateSwapchain()
-{
-  {
-    auto formats = VkAssert(mGraphics.GetPhysicalDevice().getSurfaceFormatsKHR(mSurface));
-    // find first which is not UNDEFINED
-    mFormat = vk::Format::eUndefined;
-    for(auto& format : formats)
+    if(!mVulkanSurfaceFactory)
     {
-      if(format.format != vk::Format::eUndefined && mFormat == vk::Format::eUndefined)
-      {
-        mFormat     = format.format;
-        mColorSpace = format.colorSpace;
-      }
+      return false;
     }
-  }
-
-  assert(mFormat != vk::Format::eUndefined && "No supported surface format!");
-
-  mCapabilities.reset(new vk::SurfaceCapabilitiesKHR(
-      VkAssert(mGraphics.GetPhysicalDevice().getSurfaceCapabilitiesKHR(mSurface))));
-
-  mExtent = mCapabilities->currentExtent;
 
-  CreateVulkanSwapchain();
+    // fixme: should avoid const cast :(
+    auto* allocatorCallbacks = const_cast<vk::AllocationCallbacks*>(&mGraphics.GetAllocator());
+    mSurface = mVulkanSurfaceFactory->Create( mGraphics.GetInstance(), allocatorCallbacks, mGraphics.GetPhysicalDevice() );
 
-  // initialise default render pass
-  InitialiseRenderPass();
-
-  // if successful continue with obtaining images etc. also each swapchain will obtain default renderpass
-  InitialiseSwapchain();
-
-  // prerecord command buffers per each image in order to provide layout transition
-  CreateCommandBuffers();
-}
-
-void Surface::CreateVulkanSwapchain()
-{
-  auto info = vk::SwapchainCreateInfoKHR{};
-
-  info.setClipped(true)
-      .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
-      .setImageArrayLayers(1)
-      .setImageColorSpace(mColorSpace)
-      .setImageExtent(mCapabilities->currentExtent)
-      .setImageFormat(mFormat)
-      .setImageSharingMode(vk::SharingMode::eExclusive)
-      .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment)
-      .setMinImageCount(mBufferCount)
-      .setPresentMode(vk::PresentModeKHR::eFifo)
-      .setPreTransform(mCapabilities->currentTransform)
-      .setOldSwapchain(nullptr)
-      .setPQueueFamilyIndices(nullptr)
-      .setQueueFamilyIndexCount(0)
-      .setSurface(mSurface);
-
-  mSwapchain = VkAssert(mGraphics.GetDevice().createSwapchainKHR(
-      reinterpret_cast< vk::SwapchainCreateInfoKHR& >(info), mGraphics.GetAllocator()));
-}
-
-void Surface::DestroySwapchain()
-{
-  mGraphics.GetDevice().destroySwapchainKHR(mSwapchain, mGraphics.GetAllocator());
-}
-
-void Surface::InitialiseSwapchain()
-{
-  const auto& device = mGraphics.GetDevice();
-
-  auto images = VkAssert(device.getSwapchainImagesKHR(mSwapchain));
-  assert(mBufferCount == images.size() && "Swapchain images count not equal requested value!");
-
-  {
-    auto swapImages = std::vector< SwapchainImage >{};
-
-    // for each image create framebuffer and image view
-    for(auto& image : images)
+    if(!mSurface)
     {
-      AddSwapchainImage(image, swapImages);
+      return false;
     }
 
-    mSwapImages = std::move(swapImages);
+    auto caps = VkAssert( mGraphics.GetPhysicalDevice().getSurfaceCapabilitiesKHR( mSurface ) );
+    mCurrentExtent = caps.currentExtent;
+
+    return true;
   }
 
-  if(mHasDepthStencil)
+  vk::Extent2D GetSize() const
   {
-    CreateDepthStencil();
+    return mCurrentExtent;
   }
-}
-
-void Surface::AddSwapchainImage(vk::Image image, std::vector< SwapchainImage >& swapchainImages)
-{
-  auto swapImage  = std::move(SwapchainImage{});
-  swapImage.image = NewRef<Image>( mGraphics, vk::ImageCreateInfo{}, image );
-
-  // create ImageView
-  CreateImageView(swapImage);
-
-  // Create framebuffer ( there must be already render pass and information whether
-  // we use depth or not )
-  CreateFramebuffer(swapImage);
 
-  // initialise semaphores
-  CreateSemaphores(swapImage);
+  Surface&                        mOwner;
+  Graphics&                       mGraphics;
+  std::unique_ptr<SurfaceFactory> mSurfaceFactory;
+  Dali::Integration::Graphics::Vulkan::VkSurfaceFactory* mVulkanSurfaceFactory;
+  vk::SurfaceKHR   mSurface;
+  vk::Extent2D      mCurrentExtent;
+};
 
-  swapImage.layout = vk::ImageLayout::eUndefined;
-
-  swapchainImages.push_back(std::move(swapImage));
-}
-
-void Surface::CreateImageView(SwapchainImage& swapImage)
-{
-  // Simple image view 2D as a color attachment
-  auto ivInfo = vk::ImageViewCreateInfo{};
-  ivInfo.setFormat(mFormat)
-      .setComponents(VK_COMPONENT_MAPPING_RGBA)
-      .setImage(swapImage.image->GetVkImage())
-      .setSubresourceRange(vk::ImageSubresourceRange()
-                               .setAspectMask(vk::ImageAspectFlagBits::eColor)
-                               .setBaseArrayLayer(0)
-                               .setBaseMipLevel(0)
-                               .setLayerCount(1)
-                               .setLevelCount(1))
-      .setViewType(vk::ImageViewType::e2D);
-
-  swapImage.imageView = ImageView::New( mGraphics, swapImage.image, ivInfo );
-}
-
-void Surface::CreateFramebuffer(SwapchainImage& swapImage)
-{
-  vk::FramebufferCreateInfo fbInfo;
-  fbInfo.setAttachmentCount(mHasDepthStencil ? 2 : 1)
-      .setPAttachments(&swapImage.imageView->GetVkImageView()) // todo: add depth/stencil attachment
-      .setHeight(mExtent.height)
-      .setWidth(mExtent.width)
-      .setLayers(1)
-      .setRenderPass(mDefaultRenderPass);
-
-  swapImage.framebuffer =
-      VkAssert(mGraphics.GetDevice().createFramebuffer(fbInfo, mGraphics.GetAllocator()));
-}
-
-void Surface::CreateSemaphores(SwapchainImage& swapImage)
-{
-  swapImage.acqSem =
-      VkAssert(mGraphics.GetDevice().createSemaphore(vk::SemaphoreCreateInfo(), mGraphics.GetAllocator()));
-  swapImage.presentSem =
-      VkAssert(mGraphics.GetDevice().createSemaphore(vk::SemaphoreCreateInfo(), mGraphics.GetAllocator()));
-}
+/**
+ * Surface
+ */
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
-void Surface::InitialiseRenderPass()
+SurfaceRef Surface::New( Graphics& graphics, std::unique_ptr<SurfaceFactory> surfaceFactory )
 {
-  auto att = std::vector<vk::AttachmentDescription>{ 2 };
-
-  // color attachment
-  att[0]
-      .setFormat(mFormat)
-      .setLoadOp(vk::AttachmentLoadOp::eClear)
-      .setStoreOp(vk::AttachmentStoreOp::eStore)
-      .setSamples(vk::SampleCountFlagBits::e1)
-      .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
-      .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
-      .setInitialLayout(vk::ImageLayout::eColorAttachmentOptimal)
-      .setFinalLayout(vk::ImageLayout::ePresentSrcKHR);
-
-  // optional depth/stencil attachment
-  att[1]
-      .setFormat(mDepthStencilFormat)
-      .setLoadOp(vk::AttachmentLoadOp::eClear)
-      .setStoreOp(vk::AttachmentStoreOp::eDontCare)
-      .setSamples(vk::SampleCountFlagBits::e1)
-      .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
-      .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
-      .setInitialLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal)
-      .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
-
-  auto attRef = std::array<vk::AttachmentReference, 2>{};
-  attRef[0].setLayout(vk::ImageLayout::eColorAttachmentOptimal).setAttachment(0);
-  attRef[1].setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal).setAttachment(1);
-
-  // prepare default subpass
-  vk::SubpassDescription subpass;
-  subpass.setColorAttachmentCount(1)
-      .setPColorAttachments(&attRef[0])
-      .setPDepthStencilAttachment(mHasDepthStencil ? &attRef[1] : nullptr)
-      .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics);
-
-  vk::RenderPassCreateInfo info;
-  info.setPAttachments(att.data()).setAttachmentCount(mHasDepthStencil ? 2 : 1).setPSubpasses(&subpass).setSubpassCount(1);
-
-  mDefaultRenderPass = VkAssert(mGraphics.GetDevice().createRenderPass(info, mGraphics.GetAllocator()));
+  return SurfaceRef( new Surface( graphics, std::move(surfaceFactory) ));
 }
-#pragma GCC diagnostic pop
 
-void Surface::CreateDepthStencil()
+Surface::Surface(Graphics& graphics, std::unique_ptr<SurfaceFactory> surfaceFactory )
 {
-  assert("Surface::CreateDepthStencil() not implemented!");
-  /// todo: implement
+  mImpl = std::make_unique<Impl>( *this, graphics, std::move(surfaceFactory) );
 }
 
-void Surface::DestroyDepthStencil()
-{
-  /// todo: implement
-  assert("Surface::DestroyDepthStencil() not implemented!");
-}
+Surface::~Surface() = default;
 
-void Surface::CreateCommandBuffers()
+bool Surface::Create()
 {
-  if(!mCommandPool)
-  {
-    mCommandPool = CommandPool::New( mGraphics, vk::CommandPoolCreateInfo{}.setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer) );
-  }
-
-  // allocate command buffers
-  auto cmdBuffers = std::vector< CommandBufferRef >{};
-  auto cmdInfo =
-      vk::CommandBufferAllocateInfo{}.setCommandBufferCount(1).setLevel(vk::CommandBufferLevel::ePrimary);
-
-  for(auto& swapImage : mSwapImages)
-  {
-    swapImage.layoutToColorCmdBuf = mCommandPool->NewCommandBuffer(cmdInfo);
-    swapImage.mainCmdBuf          = mCommandPool->NewCommandBuffer(cmdInfo);
-
-    // Record layout transition for each image, after transition command buffers will be re-recorded
-    // and will take in account only present -> color layout transition
-    swapImage.layoutToColorCmdBuf->Begin();
-    swapImage.layoutToColorCmdBuf->ImageLayoutTransition(swapImage.image->GetVkImage(),
-                                                         swapImage.layout,
-                                                         vk::ImageLayout::eColorAttachmentOptimal,
-                                                         vk::ImageAspectFlagBits::eColor);
-    swapImage.layoutToColorCmdBuf->End();
-    swapImage.layout = vk::ImageLayout::eColorAttachmentOptimal;
-
-    cmdBuffers.push_back(swapImage.layoutToColorCmdBuf);
-  }
-
-  // submit to the queue
-  {
-    auto& queue      = mGraphics.GetGraphicsQueue();
-    auto  fence      = Fence::New(mGraphics);
-    auto  submission = queue.Submit(cmdBuffers, fence);
-    submission->WaitForFence();
-  }
-
-  // record present to color transitions for each buffer for further reusing
-  for(auto& swapImage : mSwapImages)
-  {
-    swapImage.layoutToColorCmdBuf->Reset();
-    swapImage.layoutToColorCmdBuf->Begin();
-    swapImage.layoutToColorCmdBuf->ImageLayoutTransition(swapImage.image->GetVkImage(),
-                                                         vk::ImageLayout::ePresentSrcKHR,
-                                                         vk::ImageLayout::eColorAttachmentOptimal,
-                                                         vk::ImageAspectFlagBits::eColor);
-    swapImage.layoutToColorCmdBuf->End();
-    swapImage.layout = vk::ImageLayout::eColorAttachmentOptimal;
-  }
+  return mImpl->Initialise();
 }
 
 vk::SurfaceKHR Surface::GetSurfaceKHR() const
 {
-  return mSurface;
+  return mImpl->mSurface;
 }
 
-vk::RenderPass Surface::GetRenderPass() const
-{
-  return mDefaultRenderPass;
-}
-
-vk::Framebuffer Surface::GetFramebuffer(uint32_t index) const
-{
-  return mSwapImages[index].framebuffer;
-}
-
-ImageView& Surface::GetImageView(uint32_t index) const
-{
-  return *mSwapImages[index].imageView;
-}
-
-Image& Surface::GetImage(uint32_t index) const
+vk::Extent2D Surface::GetSize() const
 {
-  return *mSwapImages[index].image;
+  return mImpl->GetSize();
 }
 
 } // namespace Vulkan
index 9ffdc92..ff91837 100644 (file)
 
 namespace Dali
 {
+namespace Integration
+{
+namespace Graphics
+{
+class SurfaceFactory;
+}
+}
 namespace Graphics
 {
 namespace Vulkan
 {
-
-/**
- * Vulkan surface is coupled with swapchain -> one swapchain per surface
- * Swapchain won't exist until surface is used in a such way
- *
- */
+using SurfaceFactory = Dali::Integration::Graphics::SurfaceFactory;
 class Graphics;
-class CommandBuffer;
-class CommandPool;
-class Surface;
-
-using UniqueSurface       = std::unique_ptr< Surface >;
-using UniqueCommandBuffer = std::unique_ptr< CommandBuffer >;
-using UniqueCommandPool   = std::unique_ptr< CommandPool >;
-
-// simple structure describing single image of swapchain
-// non-copyable, only movable
-struct SwapchainImage
-{
-  SwapchainImage();
-  ~SwapchainImage();
-  SwapchainImage(const SwapchainImage&) = delete;
-  SwapchainImage(SwapchainImage&&)      = default;
-  SwapchainImage& operator=(const SwapchainImage&) = delete;
-  SwapchainImage& operator=(SwapchainImage&&) = default;
-
-  ImageRef        image;
-  ImageViewRef    imageView;
-  vk::Framebuffer framebuffer;
-  vk::ImageLayout layout;
-  vk::Semaphore   acqSem;
-  vk::Semaphore   presentSem;
-
-  // layout transitions, prerecorded command buffers
-  Handle<CommandBuffer> layoutToColorCmdBuf;
-  Handle<CommandBuffer> mainCmdBuf;
-};
-
-class Surface
+class Surface : public VkManaged
 {
 public:
-  Surface(Graphics& graphics, vk::SurfaceKHR surface, uint32_t bufferCount = 2,
-          bool hasDepthStencil = false);
-  ~Surface();
 
-  /**
-   * Prepares new swapchain image
-   */
-  void AcquireNextImage();
+  static SurfaceRef New( Graphics& graphics, std::unique_ptr<SurfaceFactory> surfaceFactory );
 
-  /**
-   * Presents image
-   */
-  void Present();
+  Surface(Graphics& graphics, std::unique_ptr<SurfaceFactory> surfaceFactory );
+  ~Surface() final;
 
   /**
-   *
-   * @return
-   */
-  vk::RenderPass GetRenderPass() const;
-
-  /**
-   *
-   * @param index
-   * @return
-   */
-  vk::Framebuffer GetFramebuffer(uint32_t index = -1u) const;
-
-  /**
-   *
-   * @param index
-   * @return
-   */
-  ImageView& GetImageView(uint32_t index = -1u) const;
-
-  /**
-   *
-   * @param index
-   * @return
+   * Creates surface from given factory
    */
-  Image& GetImage(uint32_t index = -1u) const;
+  bool Create();
 
   /**
    *
@@ -116,85 +57,15 @@ public:
   vk::SurfaceKHR GetSurfaceKHR() const;
 
   /**
-   * returns set of clear values for this surface
-   * @return
-   */
-  std::vector<vk::ClearValue> GetClearValues() const;
-
-  /**
    * Returns size of surface
    * @return
    */
   vk::Extent2D GetSize() const;
 
-  /**
-   * Returns primary command buffer associated with specific buffer
-   * @param index
-   * @return
-   */
-  Handle<CommandBuffer> GetCommandBuffer( uint32_t index );
-
-  /**
-   * Returns primary command buffer associated with current buffer
-   * @return
-   */
-  Handle<CommandBuffer> GetCurrentCommandBuffer();
-
-/**
-   *
-   */
-  void CreateSwapchain();
-
 private:
 
-  void CreateVulkanSwapchain();
-
-  void CreateImageView(SwapchainImage& swapImage);
-  void CreateFramebuffer(SwapchainImage& swapImage);
-  void CreateSemaphores(SwapchainImage& swapImage);
-
-  void DestroySwapchain();
-
-  void InitialiseSwapchain();
-
-  void InitialiseRenderPass();
-
-  void AddSwapchainImage(vk::Image image, std::vector< SwapchainImage >& swapchainImages);
-
-  void CreateCommandBuffers();
-
-  void CreateDepthStencil();
-
-  void DestroyDepthStencil();
-
-  void BeginRenderPass();
-
-  void EndRenderPass();
-
-  Graphics&        mGraphics;
-  vk::SurfaceKHR   mSurface;
-  vk::SwapchainKHR mSwapchain;
-
-  vk::Format       mDepthStencilFormat{vk::Format::eD16UnormS8Uint};
-  vk::Image        mDepthStencilImage;
-  vk::ImageView    mDepthStencilImageView;
-  vk::DeviceMemory mDepthStencilMemory;
-
-  Handle<CommandPool> mCommandPool;
-
-  vk::Format        mFormat;
-  vk::ColorSpaceKHR mColorSpace;
-  vk::Extent2D      mExtent;
-
-  std::vector< SwapchainImage >                 mSwapImages;
-  std::unique_ptr< vk::SurfaceCapabilitiesKHR > mCapabilities;
-
-  Handle<Fence>   mFrameFence;
-
-  vk::RenderPass mDefaultRenderPass;
-  uint32_t       mBufferCount;
-  uint32_t       mCurrentBufferIndex;
-  bool           mHasDepthStencil;
+  struct Impl;
+  std::unique_ptr<Impl> mImpl;
 };
 
 } // namespace Vulkan
diff --git a/dali/graphics/vulkan/vulkan-swapchain.cpp b/dali/graphics/vulkan/vulkan-swapchain.cpp
new file mode 100644 (file)
index 0000000..eb82f09
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h>
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
+#include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
+#include <dali/graphics/vulkan/vulkan-command-buffer.h>
+#include <dali/graphics/vulkan/vulkan-command-pool.h>
+#include <dali/graphics/vulkan/vulkan-fence.h>
+#include <dali/graphics/vulkan/vulkan-framebuffer.h>
+#include <dali/graphics/vulkan/vulkan-graphics.h>
+#include <dali/graphics/vulkan/vulkan-image.h>
+#include <dali/graphics/vulkan/vulkan-queue.h>
+#include <dali/graphics/vulkan/vulkan-surface.h>
+#include <dali/graphics/vulkan/vulkan-swapchain.h>
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+/**
+ * SwapchainBuffer stores all per-buffer data
+ */
+struct SwapchainBuffer
+{
+  /*
+   * Each buffer has own master command buffer which executes
+   * secondary buffers
+   */
+  CommandBufferRef masterCmdBuffer;
+
+  /*
+   * Each buffer has a command pool to allocate from
+   */
+  CommandPoolRef masterCommandPool;
+
+  /*
+   * Framebuffer object associated with the buffer
+   */
+  FramebufferRef framebuffer;
+
+  /*
+   * Sync primitives
+   */
+  FenceRef endOfFrameFence;
+
+  /*
+   * Buffer index
+   */
+  uint32_t index;
+
+  /*
+   * First use before presenting
+   */
+  bool firstUse;
+};
+
+struct Swapchain::Impl
+{
+  Impl( Swapchain& owner,
+        Graphics&  graphics,
+        Queue&     presentationQueue,
+        SurfaceRef surface,
+        uint32_t   bufferCount,
+        uint32_t   flags )
+  : mOwner( owner ),
+    mGraphics( graphics ),
+    mQueue( presentationQueue ),
+    mSurface( surface ),
+    mBufferCount( bufferCount ),
+    mFlags( flags )
+  {
+    mSwapchainCreateInfoKHR.setSurface( mSurface->GetSurfaceKHR() )
+      .setPreTransform( vk::SurfaceTransformFlagBitsKHR::eIdentity )
+      .setPresentMode( vk::PresentModeKHR::eFifo )
+      .setOldSwapchain( nullptr ) //@todo support surface replacement!
+      .setMinImageCount( mBufferCount )
+      .setImageUsage( vk::ImageUsageFlagBits::eColorAttachment )
+      .setImageSharingMode( vk::SharingMode::eExclusive )
+      .setImageArrayLayers( 1 )
+      .setCompositeAlpha( vk::CompositeAlphaFlagBitsKHR::eOpaque )
+      .setClipped( true )
+      .setQueueFamilyIndexCount( 0 )
+      .setPQueueFamilyIndices( nullptr );
+  }
+
+  ~Impl() = default;
+
+  Impl( const Impl& ) = delete;
+  Impl& operator=( const Impl& ) = delete;
+
+  bool Initialise()
+  {
+    if( !SetImageFormat() )
+    {
+      return false;
+    }
+
+    // get extents
+    mSwapchainExtent = mSurface->GetSize();
+
+    mSwapchainCreateInfoKHR.setImageFormat( mSwapchainImageFormat );
+    mSwapchainCreateInfoKHR.setImageExtent( mSwapchainExtent );
+    mSwapchainCreateInfoKHR.setImageColorSpace( mSwapchainColorSpace );
+
+    Create();
+
+    InitialiseSwapchainBuffers();
+
+    PrepareFramebuffers();
+
+    mFirstPresent = true;
+    return true;
+  }
+
+  bool InitialiseSwapchainBuffers()
+  {
+    mSwapchainBuffer.clear();
+    for( auto&& fb : mFramebuffers )
+    {
+      auto cmdPool   = CommandPool::New( mGraphics, vk::CommandPoolCreateInfo{}.setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
+      auto masterCmd = cmdPool->NewCommandBuffer( true );
+
+      auto swapBuffer              = SwapchainBuffer{};
+      swapBuffer.framebuffer       = fb;
+      swapBuffer.index             = 0;
+      swapBuffer.masterCmdBuffer   = masterCmd;
+      swapBuffer.masterCommandPool = cmdPool;
+      swapBuffer.endOfFrameFence   = Fence::New( mGraphics );
+      swapBuffer.firstUse          = true;
+      mSwapchainBuffer.emplace_back( swapBuffer );
+    }
+
+    return true;
+  }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+  void PrepareFramebuffers()
+  {
+    /*
+     * After creating the new swapchain we need to make sure
+     * the layout of images is correct to start with. To do so
+     * we will wait till the whole device is idle ( there should
+     * be a mechanism preventing from using the GPU past that point )
+     * and submit pipeline barriers setting up the layouts of
+     * all framebuffer images in one go. There will be no fancy
+     * synchronisation here as it's not really needed at this point.
+     * Waiting for queue or device idle should be enough.
+     */
+
+    const auto& device    = mGraphics.GetDevice();
+
+    device.waitIdle();
+
+    /*
+     * Create temporary command pool
+     */
+    auto commandPool = CommandPool::New( mGraphics );
+    auto cmdBuffer   = commandPool->NewCommandBuffer();
+
+    std::vector<vk::ImageMemoryBarrier> barriers;
+    ImageViewRef                        depthStencilImage{};
+
+    for( auto&& buffer : mSwapchainBuffer )
+    {
+      auto colorImages = buffer.framebuffer->GetAttachments( Framebuffer::AttachmentType::COLOR );
+
+      // expecting to use one depth stencil image for all swapbuffers
+      if( !depthStencilImage )
+      {
+        depthStencilImage = buffer.framebuffer->GetAttachment( Framebuffer::AttachmentType::DEPTH_STENCIL, 0u );
+      }
+
+      /*
+       * Add barriers for color images
+       */
+      for( auto&& colorImageView : colorImages )
+      {
+        auto image   = colorImageView->GetImage();
+        auto vkImage = image->GetVkImage();
+
+        vk::ImageSubresourceRange range;
+        range.setLayerCount( image->GetLayerCount() )
+          .setLevelCount( image->GetLevelCount() )
+          .setBaseMipLevel( 0 )
+          .setBaseArrayLayer( 0 )
+          .setAspectMask( vk::ImageAspectFlagBits::eColor );
+        auto colorBarrier = vk::ImageMemoryBarrier{}
+                              .setImage( vkImage )
+                              .setSubresourceRange( range )
+                              .setSrcAccessMask( vk::AccessFlags{} )
+                              .setDstAccessMask( vk::AccessFlagBits::eColorAttachmentWrite )
+                              .setOldLayout( vk::ImageLayout::eUndefined )
+                              .setNewLayout( vk::ImageLayout::eColorAttachmentOptimal );
+
+        barriers.emplace_back( colorBarrier );
+      }
+    }
+
+    /*
+     * Add barrier for depth stencil image
+     */
+    if( depthStencilImage )
+    {
+      auto image   = depthStencilImage->GetImage();
+      auto vkImage = image->GetVkImage();
+
+      vk::ImageSubresourceRange range;
+      range.setLayerCount( image->GetLayerCount() )
+        .setLevelCount( image->GetLevelCount() )
+        .setBaseMipLevel( 0 )
+        .setBaseArrayLayer( 0 )
+        .setAspectMask( vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil );
+      auto depthStencilBarrier = vk::ImageMemoryBarrier{}
+                                   .setImage( vkImage )
+                                   .setSubresourceRange( range )
+                                   .setSrcAccessMask( vk::AccessFlags{} )
+                                   .setDstAccessMask( vk::AccessFlagBits::eDepthStencilAttachmentWrite )
+                                   .setOldLayout( vk::ImageLayout::eUndefined )
+                                   .setNewLayout( vk::ImageLayout::eDepthStencilAttachmentOptimal );
+      barriers.emplace_back( depthStencilBarrier );
+    }
+
+    /*
+     * Record command buffer with pipeline barrier
+     */
+    cmdBuffer->Begin( vk::CommandBufferUsageFlagBits::eOneTimeSubmit );
+    cmdBuffer->PipelineBarrier( vk::PipelineStageFlagBits::eTopOfPipe,
+                                vk::PipelineStageFlagBits::eTopOfPipe,
+                                vk::DependencyFlags{},
+                                std::vector<vk::MemoryBarrier>{},
+                                std::vector<vk::BufferMemoryBarrier>{},
+                                barriers );
+    cmdBuffer->End();
+
+    // use presentation queue to submit the call
+    mQueue.Submit( cmdBuffer, FenceRef{} );
+    mQueue.WaitIdle();
+  }
+#pragma GCC diagnostic pop
+
+  bool SetImageFormat()
+  {
+    // obtain supported image format
+    auto formats          = VkAssert( mGraphics.GetPhysicalDevice().getSurfaceFormatsKHR( mSurface->GetSurfaceKHR() ) );
+    mSwapchainImageFormat = vk::Format::eUndefined;
+
+    for( auto&& format : formats )
+    {
+      if( format.format != vk::Format::eUndefined )
+      {
+        mSwapchainColorSpace  = format.colorSpace;
+        mSwapchainImageFormat = format.format;
+        break;
+      }
+    }
+
+    if( vk::Format::eUndefined == mSwapchainImageFormat )
+    {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Creates swapchain immediately
+   * @return
+   */
+  bool Create()
+  {
+    const auto& device    = mGraphics.GetDevice();
+    const auto& allocator = mGraphics.GetAllocator();
+
+    //@todo validation
+    mSwapchainKHR = VkAssert( device.createSwapchainKHR( mSwapchainCreateInfoKHR, allocator ) );
+
+    if( !mSwapchainKHR )
+    {
+      return false;
+    }
+
+    // pull images and create Framebuffers
+    auto images = VkAssert( device.getSwapchainImagesKHR( mSwapchainKHR ) );
+
+    // number of images must match requested buffering mode
+    if( images.size() != mBufferCount )
+    {
+      device.destroySwapchainKHR( mSwapchainKHR );
+      mSwapchainKHR = nullptr;
+      return false;
+    }
+
+    //@todo create depth-stencil image
+    auto depthStencilImageView = CreateDepthStencil();
+
+    /*
+     * CREATE FRAMEBUFFERS
+     */
+    for( auto&& image : images )
+    {
+      mFramebuffers.emplace_back( CreateFramebuffer( image ) );
+
+      // set depth/stencil if supported
+      if( depthStencilImageView )
+      {
+        mFramebuffers.back()->SetAttachment( depthStencilImageView, Framebuffer::AttachmentType::DEPTH_STENCIL, 0u );
+      }
+
+      // create framebuffer and compatible render pass right now, no need to defer it
+      mFramebuffers.back()->Commit();
+    }
+
+    return true;
+  }
+
+  /**
+   * Creates depth stencil if necessary
+   * @return
+   */
+  ImageViewRef CreateDepthStencil()
+  {
+    // create depth stencil image
+    auto dsImageRef = Image::New( mGraphics,
+                                  vk::ImageCreateInfo{}
+                                    .setFormat( vk::Format::eD24UnormS8Uint )
+                                    .setMipLevels( 1 )
+                                    .setTiling( vk::ImageTiling::eOptimal )
+                                    .setImageType( vk::ImageType::e2D )
+                                    .setArrayLayers( 1 )
+                                    .setExtent( {mSwapchainExtent.width, mSwapchainExtent.height, 1} )
+                                    .setUsage( vk::ImageUsageFlagBits::eDepthStencilAttachment )
+                                    .setSharingMode( vk::SharingMode::eExclusive )
+                                    .setInitialLayout( vk::ImageLayout::eUndefined )
+                                    .setSamples( vk::SampleCountFlagBits::e1 ) );
+
+    auto memory = mGraphics.GetDeviceMemoryManager().GetDefaultAllocator().Allocate(
+      dsImageRef, vk::MemoryPropertyFlagBits::eDeviceLocal );
+
+    dsImageRef->BindMemory( memory );
+
+    // create imageview to be used within framebuffer
+    auto dsImageViewRef = ImageView::New( mGraphics, dsImageRef );
+    return dsImageViewRef;
+  }
+
+  /**
+   * Creates a Framebuffer and compatible RenderPass
+   * @param image
+   * @return
+   */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+  FramebufferRef CreateFramebuffer( vk::Image& image )
+  {
+    auto fbRef = Framebuffer::New( mGraphics, mSwapchainExtent.width, mSwapchainExtent.height );
+
+    // Create external Image reference
+    // Note that despite we don't create VkImage, we still fill the createinfo structure
+    // as this data will be used later
+    ImageRef imageRef = Image::New( mGraphics,
+                                    vk::ImageCreateInfo{}
+                                      .setFormat( mSwapchainImageFormat )
+                                      .setSamples( vk::SampleCountFlagBits::e1 )
+                                      .setInitialLayout( vk::ImageLayout::eUndefined )
+                                      .setSharingMode( vk::SharingMode::eExclusive )
+                                      .setUsage( vk::ImageUsageFlagBits::eColorAttachment )
+                                      .setExtent( {mSwapchainExtent.width, mSwapchainExtent.height, 1} )
+                                      .setArrayLayers( 1 )
+                                      .setImageType( vk::ImageType::e2D )
+                                      .setTiling( vk::ImageTiling::eOptimal )
+                                      .setMipLevels( 1 ),
+                                    image );
+
+    // Create basic imageview ( all mipmaps, all layers )
+    ImageViewRef iv = ImageView::New( mGraphics, imageRef );
+
+    fbRef->SetAttachment( iv, Framebuffer::AttachmentType::COLOR, 0u );
+
+    return fbRef;
+  }
+#pragma GCC diagnostic pop
+
+  /**
+   * This function acquires next framebuffer
+   * @todo we should rather use roundrobin method
+   * @return
+   */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+  FramebufferRef AcquireNextFramebuffer()
+  {
+    const auto& device    = mGraphics.GetDevice();
+
+    if( !mFrameFence )
+    {
+      mFrameFence = Fence::New( mGraphics );
+    }
+
+    mCurrentBufferIndex =
+      VkAssert( device.acquireNextImageKHR( mSwapchainKHR, 1000000, nullptr, mFrameFence->GetFence() ) );
+
+    mFrameFence->Wait();
+    mFrameFence->Reset();
+
+    auto& swapBuffer = mSwapchainBuffer[mCurrentBufferIndex];
+
+    // start recording
+    auto inheritanceInfo = vk::CommandBufferInheritanceInfo{}
+      .setFramebuffer( swapBuffer.framebuffer->GetVkFramebuffer() )
+      .setRenderPass(swapBuffer.framebuffer->GetVkRenderPass())
+      .setSubpass( 0 );
+    swapBuffer.masterCmdBuffer->Reset();
+    swapBuffer.masterCmdBuffer->Begin( vk::CommandBufferUsageFlagBits::eRenderPassContinue, &inheritanceInfo );
+
+    // change layout from present to color attachment if not done yet
+    // ( swapchain must track that )
+    if(!swapBuffer.firstUse)
+    {
+      UpdateLayoutPresentToColorAttachment(swapBuffer);
+    }
+    swapBuffer.firstUse = false;
+
+    // Begins primary render pass
+    BeginPrimaryRenderPass( swapBuffer );
+
+    return swapBuffer.framebuffer;
+  }
+#pragma GCC diagnostic pop
+  void BeginPrimaryRenderPass( SwapchainBuffer& currentBuffer )
+  {
+    vk::RenderPassBeginInfo rpInfo{};
+    rpInfo.setRenderPass( currentBuffer.framebuffer->GetVkRenderPass() )
+      .setFramebuffer( currentBuffer.framebuffer->GetVkFramebuffer() )
+      .setPClearValues( currentBuffer.framebuffer->GetDefaultClearValues().data() )
+      .setClearValueCount( U32( currentBuffer.framebuffer->GetDefaultClearValues().size() ) )
+      .setRenderArea( vk::Rect2D( {0, 0}, mSurface->GetSize() ) );
+
+    currentBuffer.masterCmdBuffer->BeginRenderPass( rpInfo, vk::SubpassContents::eSecondaryCommandBuffers );
+  }
+
+  void EndPrimaryRenderPass( SwapchainBuffer& currentBuffer )
+  {
+    currentBuffer.masterCmdBuffer->EndRenderPass();
+  }
+
+  /**
+   * Performs layout transition for all the color attachments
+   * in the current framebuffer.
+   * The master command buffer must be in the recording state
+   * @param swapBuffer
+   */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+  void UpdateLayoutPresentToColorAttachment( SwapchainBuffer& swapBuffer )
+  {
+    auto& cmdBuf = swapBuffer.masterCmdBuffer;
+
+    //todo: test the state of th ebuffer, must be recording
+
+    auto attachments = swapBuffer.framebuffer->GetAttachments( Framebuffer::AttachmentType::COLOR );
+
+    std::vector<vk::ImageMemoryBarrier> barriers;
+    vk::ImageMemoryBarrier              barrier;
+    barrier.setSrcAccessMask( vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eColorAttachmentRead )
+      .setDstAccessMask( vk::AccessFlagBits::eColorAttachmentWrite )
+      .setOldLayout( vk::ImageLayout::ePresentSrcKHR )
+      .setNewLayout( vk::ImageLayout::eColorAttachmentOptimal )
+      .setSubresourceRange( vk::ImageSubresourceRange{}.setAspectMask( vk::ImageAspectFlagBits::eColor ).setBaseArrayLayer(0)
+                                                       .setBaseMipLevel(0)
+                                                       .setLevelCount(1)
+                                                       .setLayerCount(1));
+
+    for( auto&& imageView : attachments )
+    {
+      barriers.emplace_back( barrier.setImage( *imageView->GetImage() ) );
+    }
+
+    cmdBuf->PipelineBarrier( vk::PipelineStageFlagBits::eBottomOfPipe,
+                             vk::PipelineStageFlagBits::eColorAttachmentOutput,
+                             vk::DependencyFlags{},
+                             std::vector<vk::MemoryBarrier>{},
+                             std::vector<vk::BufferMemoryBarrier>{},
+                             barriers );
+  }
+#pragma GCC diagnostic pop
+
+  CommandBufferRef GetPrimaryCommandBuffer() const
+  {
+    return mSwapchainBuffer[mCurrentBufferIndex].masterCmdBuffer;
+  }
+
+  bool Present()
+  {
+    auto& swapBuffer = mSwapchainBuffer[mCurrentBufferIndex];
+
+    // end render pass
+    EndPrimaryRenderPass( swapBuffer );
+
+    // end command buffer
+    swapBuffer.masterCmdBuffer->End();
+
+    // submit
+    swapBuffer.endOfFrameFence->Reset();
+    mQueue.Submit( swapBuffer.masterCmdBuffer, swapBuffer.endOfFrameFence );
+    swapBuffer.endOfFrameFence->Wait( 0u );
+
+    // fixme: use semaphores to synchronize all previously submitted command buffers!
+    vk::PresentInfoKHR presentInfo{};
+    vk::Result result;
+    presentInfo.setPImageIndices( &mCurrentBufferIndex )
+      .setPResults( &result )
+      .setPSwapchains( &mSwapchainKHR )
+      .setSwapchainCount( 1 )
+      .setPWaitSemaphores( nullptr )
+      .setWaitSemaphoreCount( 0 );
+    mQueue.Present( presentInfo );
+
+    // just to speed things up :P
+    mQueue.WaitIdle();
+
+    return true;
+  }
+
+  // same as present but additionally waits for semaphores
+  // needed when present queue is different from graphics queue
+  bool Present( std::vector<vk::Semaphore> semaphores )
+  {
+    vk::PresentInfoKHR presentInfo{};
+    vk::Result         result{};
+    presentInfo.setPImageIndices( &mCurrentBufferIndex )
+      .setPResults( &result )
+      .setPSwapchains( &mSwapchainKHR )
+      .setSwapchainCount( 1 )
+      .setPWaitSemaphores( nullptr )
+      .setWaitSemaphoreCount( 0 );
+
+    mQueue.Present( presentInfo );
+
+    return true;
+  }
+
+  Swapchain& mOwner;
+  Graphics&  mGraphics;
+  Queue&     mQueue;
+  SurfaceRef mSurface;
+
+  uint32_t mBufferCount;
+  uint32_t mFlags;
+  uint32_t mCurrentBufferIndex;
+
+  FenceRef mFrameFence;
+
+  // swapchain framebuffers
+  std::vector<FramebufferRef> mFramebuffers;
+
+  vk::SwapchainKHR           mSwapchainKHR;
+  vk::SwapchainCreateInfoKHR mSwapchainCreateInfoKHR;
+
+  vk::Format        mSwapchainImageFormat;
+  vk::ColorSpaceKHR mSwapchainColorSpace;
+  vk::Extent2D      mSwapchainExtent;
+
+  std::vector<SwapchainBuffer> mSwapchainBuffer;
+
+  bool mFirstPresent;
+};
+
+/**
+ * Swapchain API
+ */
+SwapchainRef Swapchain::New(
+  Graphics& graphics, Queue& presentationQueue, SurfaceRef surface, uint8_t bufferCount, uint32_t flags )
+{
+  auto retval = SwapchainRef( new Swapchain( graphics, presentationQueue, surface, bufferCount, flags ) );
+
+  if( retval->mImpl->Initialise() )
+  {
+    return retval;
+  }
+
+  return SwapchainRef();
+}
+
+Swapchain::Swapchain(
+  Graphics& graphics, Queue& presentationQueue, SurfaceRef surface, uint8_t bufferCount, uint32_t flags )
+{
+  mImpl = std::make_unique<Impl>( *this, graphics, presentationQueue, surface, bufferCount, flags );
+}
+
+Swapchain::Swapchain()  = default;
+Swapchain::~Swapchain() = default;
+
+FramebufferRef Swapchain::GetCurrentFramebuffer() const
+{
+  return GetFramebuffer( mImpl->mCurrentBufferIndex );
+}
+
+FramebufferRef Swapchain::GetFramebuffer( uint32_t index ) const
+{
+  return mImpl->mSwapchainBuffer[index].framebuffer;
+}
+
+FramebufferRef Swapchain::AcquireNextFramebuffer()
+{
+  return mImpl->AcquireNextFramebuffer();
+}
+
+void Swapchain::Present()
+{
+  mImpl->Present();
+}
+
+void Swapchain::Present( std::vector<vk::Semaphore> waitSemaphores )
+{
+  mImpl->Present( waitSemaphores );
+}
+
+CommandBufferRef Swapchain::GetPrimaryCommandBuffer() const
+{
+  return mImpl->GetPrimaryCommandBuffer();
+}
+
+} // namespace Vulkan
+} // namespace Graphics
+} // namespace Dali
diff --git a/dali/graphics/vulkan/vulkan-swapchain.h b/dali/graphics/vulkan/vulkan-swapchain.h
new file mode 100644 (file)
index 0000000..23141f9
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef DALI_GRAPHICS_VULKAN_SWAPCHAIN_H
+#define DALI_GRAPHICS_VULKAN_SWAPCHAIN_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/graphics/vulkan/vulkan-types.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+class Surface;
+class Queue;
+
+/**
+ * Creates swapchain for given surface and queue
+ */
+class Swapchain : public VkManaged
+{
+public:
+
+  static SwapchainRef New( Graphics& graphics, Queue& presentationQueue, SurfaceRef surface, uint8_t bufferCount, uint32_t flags );
+
+public:
+
+  Swapchain( const Swapchain& ) = delete;
+  Swapchain& operator=( const Swapchain& ) = delete;
+
+  /**
+   * Returns current framebuffer ( the one which is rendering to )
+   * @return
+   */
+  FramebufferRef GetCurrentFramebuffer() const;
+
+  /**
+   * Returns any framebuffer from the queue
+   * @param index
+   * @return
+   */
+  FramebufferRef GetFramebuffer( uint32_t index ) const;
+
+  /**
+   * Requests for next framebuffer
+   * @return
+   */
+  FramebufferRef AcquireNextFramebuffer();
+
+  /**
+   * Returns primary command buffer associated with currently
+   * being recorded frame
+   * @return
+   */
+  CommandBufferRef GetPrimaryCommandBuffer() const;
+
+  /**
+   * Presents using default present queue, asynchronously
+   */
+  void Present();
+
+  /**
+   * Presents using default queue, synchronized with supplied semaphores
+   * @param waitSemaphores
+   */
+  void Present( std::vector<vk::Semaphore> waitSemaphores );
+
+private:
+
+  Swapchain();
+  Swapchain( Graphics& graphics, Queue& presentationQueue, SurfaceRef surface, uint8_t bufferCount, uint32_t flags );
+  ~Swapchain() override;
+
+private:
+
+  struct Impl;
+  std::unique_ptr<Impl> mImpl;
+};
+
+} // namespace Vulkan
+} // namespace Graphics
+} // namespace Dali
+#endif //DALI_GRAPHICS_VULKAN_SWAPCHAIN_H
index b0f0132..ed085fa 100644 (file)
@@ -49,15 +49,12 @@ class Queue;
 /**
  * Unique pointers to Vulkan types
  */
-using UniqueSurface       = std::unique_ptr< Surface >;
 using UniqueQueue         = std::unique_ptr< Queue >;
 
 /**
  * Reference wrappers
  */
 using QueueRef         = std::reference_wrapper< Queue >;
-using SurfaceRef       = std::reference_wrapper< Surface >;
-
 
 template< typename T >
 T VkAssert(const vk::ResultValue< T >& result, vk::Result expected = vk::Result::eSuccess)
@@ -323,7 +320,7 @@ private:
   std::atomic_uint mRefCount { 0u };
 };
 
-using FBID = uint32_t;
+using FBID = int32_t;
 
 #define NotImplemented() \
 {\
@@ -346,6 +343,9 @@ using CommandPoolRef = Handle<class CommandPool>;
 using CommandBufferRef = Handle<class CommandBuffer>;
 using GpuMemoryBlockRef = Handle<class GpuMemoryBlock>;
 using DescriptorSetRef = Handle<class DescriptorSet>;
+using SwapchainRef = Handle<class Swapchain>;
+using SurfaceRef = Handle<class Surface>;
+
 /*
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wframe-larger-than="
index 5728f21..68a9beb 100644 (file)
 #include <dali/graphics/vulkan/vulkan-types.h>
 #include <dali/graphics/vulkan/vulkan-graphics.h>
 #include <dali/graphics/vulkan/vulkan-surface.h>
+#include <dali/graphics/vulkan/vulkan-framebuffer.h>
 #include <dali/graphics-api/graphics-api-controller.h>
 #include <dali/integration-api/graphics/graphics.h>
 
+
 namespace Dali
 {
 /// fixme: substituting directly the vulkan implementation
@@ -33,6 +35,8 @@ namespace Integration
 {
 namespace Graphics
 {
+using Swapchain = Dali::Graphics::Vulkan::Swapchain;
+using SwapchainRef = Dali::Graphics::Vulkan::SwapchainRef;
 
 Graphics::Graphics()
 {
@@ -52,6 +56,7 @@ Graphics::~Graphics()
 Dali::Graphics::FBID Graphics::Create(
   std::unique_ptr<Dali::Integration::Graphics::SurfaceFactory> surfaceFactory)
 {
+  //@todo do we really need to have a surface that early???
 
   // create surface
   auto retval = mGraphicsImpl->CreateSurface(std::move(surfaceFactory));
@@ -59,8 +64,11 @@ Dali::Graphics::FBID Graphics::Create(
   // create device
   mGraphicsImpl->CreateDevice();
 
+  // create swapchain from surface
+  auto surface = mGraphicsImpl->GetSurface( retval );
+
   // create swapchain
-  mGraphicsImpl->GetSurface( retval ).CreateSwapchain();
+  mGraphicsImpl->CreateSwapchainForSurface( surface );
 
   return retval;
 }
@@ -73,9 +81,9 @@ Dali::Graphics::FBID Graphics::CreateSurface(
 
 void Graphics::PreRender(Dali::Graphics::FBID framebufferId)
 {
-  assert(framebufferId != 0u && "Invalid FBID!");
-  auto &surface = mGraphicsImpl->GetSurface(framebufferId);
-  surface.AcquireNextImage();
+  assert(framebufferId != 0 && "Invalid FBID!");
+  auto swapchain = mGraphicsImpl->GetSwapchainForFBID( framebufferId );
+  swapchain->AcquireNextFramebuffer();
 }
 
 Dali::Graphics::API::Controller& Graphics::GetController()
@@ -88,9 +96,8 @@ Dali::Graphics::API::Controller& Graphics::GetController()
  */
 void Graphics::PostRender(Dali::Graphics::FBID framebufferId)
 {
-  assert(framebufferId != 0u && "Invalid FBID!");
-  auto &surface = mGraphicsImpl->GetSurface(framebufferId);
-  surface.Present();
+  auto swapchain = mGraphicsImpl->GetSwapchainForFBID( framebufferId );
+  swapchain->Present();
 }
 
 void IncludeThisLibrary()
index 597f2df..8b98599 100644 (file)
@@ -32,7 +32,7 @@ namespace API
 class Controller;
 }
 // frame buffer id
-using FBID = uint32_t;
+using FBID = int32_t;
 
 namespace Vulkan
 {
index 97bd3ef..313aae8 100644 (file)
@@ -30,6 +30,9 @@ class SurfaceFactory
 public:
   SurfaceFactory()          = default;
   virtual ~SurfaceFactory() = default;
+
+  SurfaceFactory( const SurfaceFactory& ) = delete;
+  SurfaceFactory& operator=( const SurfaceFactory& ) = delete;
 };
 
 } // Namespace Graphics