Instance, device, surface and swapchain work.
Change-Id: I7a3816a885761072c9b42c7acc925a79f337d130
# Add graphics source files here
graphics_src_files = \
- $(graphics_src_dir)/graphics-controller.cpp
+ $(graphics_src_dir)/graphics-controller.cpp \
+ $(graphics_src_dir)/graphics-controller.cpp \
+ $(graphics_src_dir)/graphics-logical-device.cpp \
+ $(graphics_src_dir)/graphics-physical-device.cpp \
+ $(graphics_src_dir)/graphics-surface.cpp \
+ $(graphics_src_dir)/graphics-swapchain.cpp \
+ $(graphics_src_dir)/vulkan/image.cpp \
+ $(graphics_src_dir)/vulkan/device-memory.cpp \
+ $(graphics_src_dir)/vulkan/command-queue.cpp \
+ $(graphics_src_dir)/vulkan/surface.cpp \
+ $(graphics_src_dir)/vulkan/logical-device.cpp \
+ $(graphics_src_dir)/vulkan/command-buffer.cpp \
+ $(graphics_src_dir)/vulkan/image-view.cpp \
+ $(graphics_src_dir)/vulkan/command-pool.cpp \
+ $(graphics_src_dir)/vulkan/framebuffer.cpp \
+ $(graphics_src_dir)/vulkan/physical-device.cpp \
+ $(graphics_src_dir)/vulkan/swapchain.cpp \
+ $(graphics_src_dir)/vulkan/buffer.cpp
+
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+
+GraphicsSwapchain GraphicsLogicalDevice::CreateSwapchain(const GraphicsSurface& surface,
+ uint32_t bufferCount,
+ DepthStencil depthStencil,
+ VSyncMode enforceVSync)
+{
+ return GetObject()->CreateSwapchain(surface, bufferCount, depthStencil, enforceVSync);
+}
+}
+}
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_GRAPHICS_LOGICAL_DEVICE_H
+#define DALI_CORE_GRAPHICS_GRAPHICS_LOGICAL_DEVICE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-swapchain.h>
+#include <dali/graphics/integration/graphics-logical-device-base.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+
+using GraphicsLogicalDeviceHandle = VkHandleBase< GraphicsLogicalDeviceBase >;
+
+class GraphicsLogicalDevice : public GraphicsLogicalDeviceHandle
+{
+public:
+ GraphicsLogicalDevice(GraphicsLogicalDeviceBase* impl = nullptr)
+ : GraphicsLogicalDeviceHandle{impl}
+ {
+ }
+
+ using GraphicsLogicalDeviceHandle::operator=;
+
+ GraphicsSwapchain CreateSwapchain(const GraphicsSurface& surface,
+ uint32_t bufferCount,
+ DepthStencil depthStencil,
+ VSyncMode enforceVSync);
+};
+
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICS_GRAPHICS_LOGICAL_DEVICE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-physical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+
+GraphicsPhysicalDevice GraphicsPhysicalDevice::New()
+{
+ return GraphicsPhysicalDevice(nullptr);
+}
+
+bool GraphicsPhysicalDevice::Initialise(const ExtensionNameList& extensions, const ValidationLayerFlags2& layers)
+{
+ return GetObject()->Initialise(extensions, layers);
+}
+
+bool GraphicsPhysicalDevice::IsExtensionAvailable(const std::string& instanceExtensionName) const
+{
+ return GetObject()->IsExtensionAvailable(instanceExtensionName);
+}
+
+bool GraphicsPhysicalDevice::IsLayerAvailable(const std::string& instanceLayerName) const
+{
+ return GetObject()->IsLayerAvailable(instanceLayerName);
+}
+
+bool GraphicsPhysicalDevice::ChoosePhysicalDevice(const PhysicalDeviceFlags& flags)
+{
+ return GetObject()->ChoosePhysicalDevice(flags);
+}
+
+GraphicsLogicalDevice GraphicsPhysicalDevice::CreateLogicalDevice(const ExtensionNameList& enabledExtensions)
+{
+ return GetObject()->CreateLogicalDevice(enabledExtensions);
+}
+
+GraphicsLogicalDevice GraphicsPhysicalDevice::CreateLogicalDevice()
+{
+ return CreateLogicalDevice(ExtensionNameList());
+}
+
+GraphicsSurface GraphicsPhysicalDevice::CreateSurface(const NativeSurfaceCreateInfo& info)
+{
+ return GetObject()->CreateSurface(info);
+}
+
+} // Graphics
+} // Dali
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_PHYSICAL_DEVICE_H
+#define DALI_CORE_GRAPHICS_PHYSICAL_DEVICE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-logical-device.h>
+#include <dali/graphics/graphics-surface.h>
+#include <dali/graphics/integration/graphics-physical-device-base.h>
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+
+class GraphicsPhysicalDevice : public VkHandleBase< Integration::GraphicsPhysicalDeviceBase >
+{
+public:
+ GraphicsPhysicalDevice(Integration::GraphicsPhysicalDeviceBase* impl = nullptr)
+ : VkHandleBase{impl}
+ {
+ }
+
+ using VkHandleBase::operator=;
+
+public:
+ /**
+ * Creates new uninitialised physical device
+ * @return
+ */
+ static GraphicsPhysicalDevice New();
+
+ /**
+ *
+ * @param extensions
+ * @param layers
+ * @return
+ */
+ bool Initialise(const ExtensionNameList& extensions, const ValidationLayerFlags2& layers);
+
+ /**
+ *
+ * @param instanceExtensionName
+ * @return
+ */
+ bool IsExtensionAvailable(const std::string& instanceExtensionName) const;
+
+ /**
+ *
+ * @param instanceExtensionName
+ * @return
+ */
+ bool IsLayerAvailable(const std::string& instanceExtensionName) const;
+
+ /**
+ *
+ * @param flags
+ * @return
+ */
+ bool ChoosePhysicalDevice(const PhysicalDeviceFlags& flags = 0u);
+
+ /**
+ * Creates logical device from the physical device
+ * @param enabledExtensions
+ * @return
+ */
+ GraphicsLogicalDevice CreateLogicalDevice(const ExtensionNameList& enabledExtensions);
+
+ /**
+ *
+ * @return
+ */
+ GraphicsLogicalDevice CreateLogicalDevice();
+
+ // temporary solution to bind physical device with surface
+ /**
+ *
+ * @param info
+ * @return
+ */
+ GraphicsSurface CreateSurface(const NativeSurfaceCreateInfo& info);
+};
+
+using PhysicalDeviceHandle = VkHandleBase< Integration::GraphicsPhysicalDeviceBase >;
+
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICSPHYSICALDEVICE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-surface.h>
+#include <dali/graphics/integration/graphics-surface-base.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+bool GraphicsSurface::Initialise()
+{
+ return GetObject()->Initialise();
+}
+
+bool GraphicsSurface::Replace()
+{
+ return GetObject()->Replace();
+}
+
+bool GraphicsSurface::Destroy()
+{
+ return GetObject()->Destroy();
+}
+
+uint32_t GraphicsSurface::GetWidth()
+{
+ return GetObject()->GetWidth();
+}
+
+uint32_t GraphicsSurface::GetHeight()
+{
+ return GetObject()->GetHeight();
+}
+
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_SURFACE_H
+#define DALI_CORE_GRAPHICS_SURFACE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/integration/graphics-surface-base.h>
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+
+enum class NativeSurfaceType
+{
+ UNDEFINED,
+ X11,
+ XCB,
+ WAYLAND,
+ ANDROID_NATIVE_WINDOW,
+ WIN32
+};
+
+struct NativeSurfaceCreateInfo
+{
+ NativeSurfaceCreateInfo(NativeSurfaceType type) : surfaceType{type}
+ {
+ }
+ NativeSurfaceType surfaceType;
+};
+
+using SurfaceHandle = VkHandleBase< Integration::GraphicsSurfaceBase >;
+
+class GraphicsSurface : public SurfaceHandle
+{
+public:
+ GraphicsSurface(Integration::GraphicsSurfaceBase* impl = nullptr) : SurfaceHandle{impl}
+ {
+ }
+ using SurfaceHandle::operator=;
+
+ template< typename T, typename... ARGS >
+ static GraphicsSurface New(const GraphicsPhysicalDevice& physicalDevice, ARGS&&... args)
+ {
+ GraphicsSurface retval = (new T(physicalDevice, args...));
+ if(!retval.Initialise())
+ {
+ retval = nullptr;
+ }
+ return retval;
+ }
+
+ bool Initialise();
+ bool Replace();
+ bool Destroy();
+ uint32_t GetWidth();
+ uint32_t GetHeight();
+
+private:
+};
+}
+}
+
+#endif //DALI_CORE_GRRAPHICSSURFACE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include "graphics-swapchain.h"
+
+#include <dali/graphics/integration/graphics-swapchain-base.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+
+namespace
+{
+Integration::GraphicsSwapchainBase* GetImpl(SwapchainHandle* handle)
+{
+ return handle->GetObject();
+}
+}
+
+void GraphicsSwapchain::Initialise()
+{
+ GetImpl(this)->Initialise();
+}
+
+/**
+ * Acquires next renderable frame from swapchain
+ */
+void GraphicsSwapchain::AcquireFrame()
+{
+ GetImpl(this)->AcquireFrame();
+}
+
+/**
+ * Presents frame
+ */
+void GraphicsSwapchain::PresentFrame()
+{
+ GetImpl(this)->PresentFrame();
+}
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_SWAPCHAIN_H
+#define DALI_CORE_GRAPHICS_SWAPCHAIN_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/integration/graphics-swapchain-base.h>
+#include <dali/graphics/vulkan/common.h>
+
+#include <cinttypes>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+
+/**
+ * DepthStencil enum values
+ */
+enum class DepthStencil
+{
+ NONE,
+ DEPTH_16,
+ DEPTH_24,
+ DEPTH_16_STENCIL_8,
+ DEPTH_24_STENCIL_8
+};
+
+/**
+ * Vsync mode values
+ */
+enum class VSyncMode
+{
+ DISABLED = 0,
+ ENABLED = 1
+};
+
+class GraphicsContext;
+
+using SwapchainHandle = VkHandleBase< Integration::GraphicsSwapchainBase >;
+
+class GraphicsSwapchain : public SwapchainHandle
+{
+public:
+
+ GraphicsSwapchain(Integration::GraphicsSwapchainBase* o = nullptr) : SwapchainHandle{o} {};
+
+ using SwapchainHandle::operator=;
+
+ /**
+ * Initialises GraphicsSwapchain
+ */
+ void Initialise();
+
+ /**
+ * Acquires next renderable frame from swapchain
+ */
+ void AcquireFrame();
+
+ /**
+ * Presents current frame
+ */
+ void PresentFrame();
+};
+}
+}
+
+#endif //DALI_CORE_GRAPHICSSWAPCHAIN_H
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_GRAPHICS_LOGICAL_DEVICE_BASE_H
+#define DALI_CORE_GRAPHICS_GRAPHICS_LOGICAL_DEVICE_BASE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-swapchain.h>
+#include <dali/graphics/vulkan/common.h>
+#include <cinttypes>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+class GraphicsSurface;
+
+// base class for context implementation
+class GraphicsLogicalDeviceBase : public VkObject
+{
+public:
+ virtual bool Initialise() = 0;
+
+ virtual GraphicsSwapchain CreateSwapchain(const GraphicsSurface& surface,
+ uint32_t bufferCount,
+ DepthStencil depthStencil,
+ VSyncMode enforceVSync) = 0;
+
+ virtual GraphicsPhysicalDevice GetGraphicsPhysicalDevice() const = 0;
+};
+
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICS_GRAPHICS_LOGICAL_DEVICE_BASE_H
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_PHYSCIAL_DEVICE_BASE_H
+#define DALI_CORE_GRAPHICS_PHYSCIAL_DEVICE_BASE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-logical-device.h>
+#include <dali/graphics/graphics-surface.h>
+#include <dali/graphics/vulkan/common.h>
+namespace Dali
+{
+namespace Graphics
+{
+namespace Integration
+{
+
+// abstract class for building the graphics adaptor
+class GraphicsPhysicalDeviceBase : public VkObject
+{
+public:
+ /**
+ *
+ * @param extensions
+ * @param layers
+ * @return
+ */
+ virtual bool Initialise(const ExtensionNameList& extensions, const ValidationLayerFlags2& layers) = 0;
+
+ /**
+ *
+ * @param instanceExtensionName
+ * @return
+ */
+ virtual bool IsExtensionAvailable(const std::string& instanceExtensionName) = 0;
+
+ /**
+ *
+ * @param instanceExtensionName
+ * @return
+ */
+ virtual bool IsLayerAvailable(const std::string& instanceExtensionName) = 0;
+
+ /**
+ *
+ * @param surface
+ * @return
+ */
+ virtual GraphicsLogicalDevice CreateLogicalDevice(const ExtensionNameList& enabledExtensions) = 0;
+
+ /**
+ *
+ * @param flags
+ * @return
+ */
+ virtual bool ChoosePhysicalDevice(const PhysicalDeviceFlags& flags) = 0;
+
+ /**
+ *
+ * @param flags
+ */
+ virtual void SetValidationDebugChannels(const ValidationChannelFlags& flags) = 0;
+
+ /**
+ *
+ * @param info
+ * @return
+ */
+ virtual GraphicsSurface CreateSurface(const NativeSurfaceCreateInfo& info) = 0;
+};
+} // Integration
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICS_PHYSCIAL_DEVICE_BASE_H
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_SURFACE_BASE_H
+#define DALI_CORE_GRAPHICS_SURFACE_BASE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+
+namespace Vulkan
+{
+
+namespace Internal
+{
+class GraphicsSurfaceBase : public VkObject
+{
+private:
+ GraphicsSurfaceBase() = default;
+
+public:
+ //GraphicsSurfaceBase(const GraphicsPhysicalDevice &adaptor)
+ //{};
+ GraphicsSurfaceBase(const GraphicsPhysicalDevice &physicalDevice){};
+ virtual ~GraphicsSurfaceBase() = default;
+
+ virtual bool Initialise() = 0;
+
+ virtual bool Replace() = 0;
+
+ virtual bool Destroy() = 0;
+
+ virtual uint32_t GetWidth() = 0;
+
+ virtual uint32_t GetHeight() = 0;
+};
+}
+
+} // Vulkan
+
+// todo: remove 'internal' namespace
+namespace Integration
+{
+using GraphicsSurfaceBase = Vulkan::Internal::GraphicsSurfaceBase;
+} // Integration
+} // Graphics
+} // Dali
+
+#endif // DALI_CORE_GRAPHICS_SURFACE_BASE_H
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_SWAPCHAIN_BASE_H
+#define DALI_CORE_GRAPHICS_SWAPCHAIN_BASE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Integration
+{
+
+class GraphicsSwapchainBase : public VkObject
+{
+public:
+ GraphicsSwapchainBase() = default;
+ virtual ~GraphicsSwapchainBase() = default;
+
+ /**
+ * Initialises swapchain
+ * @return
+ */
+ virtual bool Initialise() = 0;
+
+ /**
+ * Called for new frame to acquire new frame buffer
+ * @return
+ */
+ virtual bool AcquireFrame() = 0;
+
+ /**
+ * Called at the end of frame to present current frame buffer
+ * @return
+ */
+ virtual bool PresentFrame() = 0;
+
+};
+
+} // Integration
+} // Graphics
+} // Dali
+
+
+#endif // DALI_CORE_GRAPHICS_SWAPCHAIN_BASE_H
--- /dev/null
+//
+// Created by adam.b on 23/03/17.
+//
+
+#include <vulkan/vulkan.hpp>
+#ifdef __linux__
+#include <X11/Xlib.h>
+#include <unistd.h>
+#endif
+
+
+#include <dali/graphics/graphics-physical-device.h>
+#include <dali/graphics/vulkan/physical-device.h>
+#include <dali/graphics/vulkan/surface/xcb-surface.h>
+#include <dali/graphics/vulkan/surface/xlib-surface.h>
+
+// vulkan specific
+#include <dali/graphics/vulkan/command-queue.h>
+#include <dali/graphics/vulkan/device-memory.h>
+#include <dali/graphics/vulkan/image.h>
+#include <dali/graphics/vulkan/logical-device.h>
+#include <dali/graphics/vulkan/swapchain.h>
+
+using namespace Dali::Graphics;
+
+namespace
+{
+Vulkan::CommandPool gSecondaryCommandPool{nullptr};
+Vulkan::Image gImage{nullptr};
+}
+
+struct TestWindow
+{
+ int width, height;
+ Display* display;
+ ::Window window;
+ int defaultScreen;
+} gWnd;
+
+void InitWindow(int width, int height)
+{
+ // 1. Create Window ( done by DALI
+ gWnd.width = width;
+ gWnd.height = height;
+ gWnd.display = XOpenDisplay(nullptr);
+ gWnd.defaultScreen = DefaultScreen(gWnd.display);
+ gWnd.window = XCreateSimpleWindow(gWnd.display, RootWindow(gWnd.display, gWnd.defaultScreen), 0, 0,
+ gWnd.width, gWnd.height, 1, BlackPixel(gWnd.display, gWnd.defaultScreen),
+ WhitePixel(gWnd.display, gWnd.defaultScreen));
+
+ XSelectInput(gWnd.display, gWnd.window, ExposureMask | KeyPressMask);
+ XMapWindow(gWnd.display, gWnd.window);
+}
+
+struct XcbWindow
+{
+ xcb_connection_t* xcb_connection;
+ xcb_screen_t* xcb_screen;
+ xcb_window_t xcb_window;
+ int width, height;
+} gXcb;
+
+void initXcbWindow(int width, int height)
+{
+ // 1. Create Window ( done by DALi )
+ gXcb.width = width;
+ gXcb.height = height;
+ int screenNum(0);
+ xcb_connection_t* connection = xcb_connect(NULL, &screenNum);
+ const xcb_setup_t* setup = xcb_get_setup(connection);
+ xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
+ for(int i = 0; i < screenNum; ++i)
+ xcb_screen_next(&iter);
+
+ xcb_screen_t* screen = iter.data;
+ xcb_window_t window = xcb_generate_id(connection);
+
+ uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
+ uint32_t values[] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS};
+
+ xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, gXcb.width,
+ gXcb.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values);
+
+ xcb_map_window(connection, window);
+ const uint32_t coords[] = {100, 100};
+ xcb_configure_window(connection, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
+ xcb_flush(connection);
+
+ gXcb.xcb_connection = connection;
+ gXcb.xcb_window = window;
+ gXcb.xcb_screen = screen;
+}
+
+void createTexture(const Vulkan::LogicalDevice& device, const Vulkan::CommandBuffer& commandBuffer)
+{
+ // create buffer
+ const int TEXTURE_SIZE = 1024 * 1024 * 4;
+
+ vk::BufferCreateInfo bufInfo;
+ bufInfo.setUsage(vk::BufferUsageFlagBits::eTransferSrc)
+ .setSharingMode(vk::SharingMode::eExclusive)
+ .setQueueFamilyIndexCount(0)
+ .setPQueueFamilyIndices(nullptr)
+ .setSize(TEXTURE_SIZE);
+
+ auto textureBuffer = Vulkan::Buffer::New(device, bufInfo);
+ auto memory = device.AllocateBufferMemory(textureBuffer, vk::MemoryPropertyFlagBits::eHostVisible, true);
+ void* ptr = memory.Map(0, VK_WHOLE_SIZE);
+
+ // Load texture directly into the buffer
+ FILE* f = fopen("/tmp/out.rgba", "rb");
+ fseek(f, 0, SEEK_END);
+ assert(ftell(f) == bufInfo.size);
+ fseek(f, 0, SEEK_SET);
+ fread(ptr, 1, bufInfo.size, f);
+ fclose(f);
+
+ // unmap and flush memory
+ memory.Unmap();
+ memory.Flush();
+
+ // create 2D texture image
+ vk::ImageCreateInfo imageInfo;
+ imageInfo.setSharingMode(vk::SharingMode::eExclusive);
+ imageInfo.setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst);
+ imageInfo.setInitialLayout(vk::ImageLayout::eUndefined);
+ imageInfo.setSamples(vk::SampleCountFlagBits::e1);
+ imageInfo.setExtent(vk::Extent3D{1024, 1024, 1});
+ imageInfo.setFormat(vk::Format::eR8G8B8A8Unorm);
+ imageInfo.setTiling(vk::ImageTiling::eOptimal);
+ imageInfo.setMipLevels(1);
+ imageInfo.setArrayLayers(1);
+ imageInfo.setImageType(vk::ImageType::e2D);
+
+ // create vulkan image
+ auto image = Vulkan::Image::New(device, imageInfo);
+ auto imageMemory = device.AllocateImageMemory(image, vk::MemoryPropertyFlagBits::eDeviceLocal, true);
+
+ if(!gSecondaryCommandPool)
+ {
+ gSecondaryCommandPool = device.CreateCommandPool(QueueType::TRANSFER, true, true);
+ }
+
+ // record
+ Vulkan::CommandBuffer cmdBuf = gSecondaryCommandPool.AllocateCommandBuffer(true);
+ vk::BufferImageCopy region;
+ region.setImageExtent({1024, 1024, 1});
+ region.setImageSubresource(vk::ImageSubresourceLayers()
+ .setAspectMask(vk::ImageAspectFlagBits::eColor)
+ .setMipLevel(0)
+ .setLayerCount(1)
+ .setBaseArrayLayer(0));
+
+ auto layoutBarrier =
+ image.GetLayoutChangeBarrier(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlags(),
+ vk::AccessFlagBits::eTransferWrite, vk::ImageAspectFlagBits::eColor);
+
+ cmdBuf.Begin(true);
+ cmdBuf->pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTopOfPipe,
+ vk::DependencyFlags(), 0, nullptr, 0, nullptr, 1, &layoutBarrier);
+ cmdBuf->copyBufferToImage(*textureBuffer, *image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion);
+
+ image.SetLayout( vk::ImageLayout::eTransferDstOptimal );
+ auto layoutBarrier2 =
+ image.GetLayoutChangeBarrier(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlags(),
+ vk::AccessFlagBits::eTransferWrite, vk::ImageAspectFlagBits::eColor);
+
+
+ cmdBuf->pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTopOfPipe,
+ vk::DependencyFlags(), 0, nullptr, 0, nullptr, 1, &layoutBarrier2);
+
+ image.SetLayout( vk::ImageLayout::eTransferSrcOptimal );
+ cmdBuf.End();
+
+ auto queue = device.GetCommandQueue(0, QueueType::TRANSFER);
+ queue.Submit(&cmdBuf, 1, nullptr);
+
+ // should use fence
+ queue.WaitIdle();
+
+ gImage = image;
+ return;
+}
+
+int main(int argc, char** argv)
+{
+
+ InitWindow(720, 360);
+ // make physical device from vulkan device ( should be done through some sort of
+ // implementation factory )
+ GraphicsPhysicalDevice physDevice(Vulkan::PhysicalDevice::New());
+ ExtensionNameList list;
+
+ // check extensions ( vulkan specific )
+
+ NativeSurfaceType surfaceType = NativeSurfaceType::UNDEFINED;
+
+ if(physDevice.IsExtensionAvailable(VK_KHR_SURFACE_EXTENSION_NAME))
+ list.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
+ if(physDevice.IsExtensionAvailable(VK_KHR_XCB_SURFACE_EXTENSION_NAME))
+ {
+ list.emplace_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
+ //surfaceType = NativeSurfaceType::XCB;
+ }
+ if(physDevice.IsExtensionAvailable(VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
+ {
+ list.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
+ if(surfaceType == NativeSurfaceType::UNDEFINED)
+ surfaceType = NativeSurfaceType::X11;
+ }
+
+ physDevice.Initialise(list,
+ ValidationLayerFlags2() | ValidationLayerBit2::CORE_VALIDATION |
+ ValidationLayerBit2::STANDARD_VALIDATION |
+ ValidationLayerBit2::PARAMETER_VALIDATION | ValidationLayerBit2::API_DUMP);
+
+ // reporting on all channels
+ //physDevice.SetValidationDebugChannels(ValidationChannelBit::ALL);
+
+ bool result = physDevice.ChoosePhysicalDevice(PhysicalDeviceBit::ANY);
+
+ GraphicsSurface surface{nullptr};
+
+ if(surfaceType == NativeSurfaceType::XCB)
+ {
+ XcbSurfaceCreateInfo info;
+ info.connection = gXcb.xcb_connection;
+ info.window = gXcb.xcb_window;
+ surface = physDevice.CreateSurface(info);
+ }
+ else
+ {
+ XlibSurfaceCreateInfo info;
+ info.display = gWnd.display;
+ info.window = gWnd.window;
+ surface = physDevice.CreateSurface(info);
+ }
+ auto logicalDevice = physDevice.CreateLogicalDevice();
+
+ auto swapchain = logicalDevice.CreateSwapchain(surface, 2, DepthStencil::NONE, VSyncMode::DISABLED);
+
+ // obtain vulkan interface
+ auto vkSwapchain = swapchain.Cast< Vulkan::Swapchain >();
+ auto vkDevice = logicalDevice.Cast< Vulkan::LogicalDevice >();
+
+ createTexture(vkDevice, vkSwapchain.GetCurrentCommandBuffer());
+
+ bool running = true;
+
+ while(running)
+ {
+ swapchain.AcquireFrame();
+ auto cmdbuf = vkSwapchain.GetCurrentCommandBuffer();
+ vk::ImageCopy region;
+
+ vk::ImageSubresourceLayers subres;
+ subres.setBaseArrayLayer(0).setAspectMask(vk::ImageAspectFlagBits::eColor).setLayerCount(1).setMipLevel(0);
+
+ region.setExtent({100, 100, 1})
+ .setDstOffset({0, 0, 0})
+ .setSrcOffset({0, 0, 0})
+ .setSrcSubresource(subres)
+ .setDstSubresource(subres);
+
+ cmdbuf->copyImage(*gImage, gImage.GetLayout(), vkSwapchain.GetCurrentImage(),
+ vk::ImageLayout::eColorAttachmentOptimal, 1, ®ion);
+ usleep(1000);
+ swapchain.PresentFrame();
+ }
+
+ return 0;
+}
+
+int main_(int argc, char** argv)
+{
+ initXcbWindow(720, 360);
+
+#if 0
+ // using template argument to pick adaptor implementation
+ GraphicsPhysicalDevice adaptor = GraphicsPhysicalDevice::GraphicsPhysicalDevice< Internal::VulkanAdaptor >();
+ ExtensionNameList list;
+
+ // check extension
+ if(adaptor.IsExtensionAvailable(VK_KHR_SURFACE_EXTENSION_NAME))
+ list.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
+ if(adaptor.IsExtensionAvailable(VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
+ list.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
+ if(adaptor.IsExtensionAvailable(VK_KHR_XCB_SURFACE_EXTENSION_NAME))
+ list.emplace_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
+
+ // initialise
+ adaptor.Initialise(list,
+ ValidationLayerFlags()
+ | ValidationLayerBit2::CORE_VALIDATION |
+ ValidationLayerBit2::STANDARD_VALIDATION |
+ ValidationLayerBit2::PARAMETER_VALIDATION | ValidationLayerBit2::API_DUMP);
+
+ // reporting on all channels
+ adaptor.SetValidationDebugChannels(ValidationChannelBit::ALL);
+
+ // choose first available physical adaptor
+ bool result = adaptor.ChoosePhysicalDevice(PhysicalDeviceBit::ANY);
+
+ if(!result) // no requested device available ( maybe adding enumeration )
+ {
+ // fixme, something went very wrong
+ }
+
+ // create surface for X11 ( could be templated GraphicsPhysicalDevice function? )
+ auto surface = adaptor.CreateSurface< Internal::GraphicsXcbSurface >(adaptor, gXcb.xcb_connection, gXcb.xcb_window);
+
+ if(!surface)
+ {
+ VkLog("No surface dammit!");
+ }
+
+ // create context
+ auto context = adaptor.CreateContext(surface);
+
+ // create swapchain ( 2 buffers )
+ auto swapchain = context.CreateSwapchain(surface, 3, DepthStencil::NONE, true);
+
+ while( 1 )
+ {
+ swapchain.AcquireFrame();
+ usleep(1000);
+ //swapchain.SwapBuffers( true );
+ swapchain.PresentFrame();
+ }
+
+ return 0;
+}
+
+int _main(int argc, char** argv)
+{
+#if 0
+ InitWindow(720, 360);
+
+ GraphicsPhysicalDevice adaptor;
+ ExtensionNameList list;
+
+ // check extension
+ if(adaptor.IsExtensionAvailable(VK_KHR_SURFACE_EXTENSION_NAME))
+ list.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
+ if(adaptor.IsExtensionAvailable(VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
+ list.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
+
+ // initialise
+ adaptor.Initialise(list, ValidationLayerFlags() |
+ ValidationLayerBit2::CORE_VALIDATION | ValidationLayerBit2::STANDARD_VALIDATION |
+ ValidationLayerBit2::PARAMETER_VALIDATION|ValidationLayerBit2::API_DUMP);
+
+ // reporting on all channels
+ adaptor.SetValidationDebugChannels( ValidationChannelBit::ALL );
+
+ // choose first available physical adaptor
+ bool result = adaptor.ChoosePhysicalDevice(PhysicalDeviceBit::ANY);
+
+ if( !result ) // no requested device available ( maybe adding enumeration )
+ {
+ // fixme, something went very wrong
+ }
+
+ // create surface for X11 ( could be templated GraphicsPhysicalDevice function? )
+ //auto& surface = GraphicsSurfaceBase::CreateSurface<GraphicsXlibSurface>( adaptor, gWnd.display, gWnd.window );
+ auto& surface = adaptor.CreateSurface<GraphicsXlibSurface>( adaptor, gWnd.display, gWnd.window );
+
+ if( surface == nullptr )
+ {
+ // surface invalid :((((
+ }
+ // create context
+ GraphicsContext context = adaptor.CreateContext(surface);
+
+ // create swapchain with 2 buffers
+ GraphicsSwapchain swapchain = context.CreateSwapchain( surface, 2 );
+
+#endif
+#endif
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/buffer.h>
+#include <dali/graphics/vulkan/device-memory.h>
+#include <dali/graphics/vulkan/logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+// Implementation
+
+class BufferImpl : public VkObject
+{
+public:
+ BufferImpl(const LogicalDevice& device, const vk::BufferCreateInfo& info)
+ : mDevice(device), mCreateInfo(info)
+ {
+ }
+
+ virtual ~BufferImpl();
+
+ bool Initialise();
+
+ const vk::Buffer& GetVkBuffer() const
+ {
+ return mBuffer;
+ }
+
+ const DeviceMemory& GetDeviceMemory() const
+ {
+ return mDeviceMemory;
+ }
+
+ bool BindDeviceMemory(const DeviceMemory& memory, size_t offset);
+
+private:
+ LogicalDevice mDevice{nullptr};
+ DeviceMemory mDeviceMemory{nullptr}; // bound device memory
+ vk::BufferCreateInfo mCreateInfo{};
+ vk::Buffer mBuffer{nullptr};
+ size_t mMemoryBoundOffset{0u};
+};
+
+BufferImpl::~BufferImpl()
+{
+ if(mBuffer)
+ {
+ mDevice.GetVkDevice().destroyBuffer(mBuffer, mDevice.GetVkAllocator());
+ }
+}
+
+bool BufferImpl::Initialise()
+{
+ return VkTestBool(mDevice.GetVkDevice().createBuffer(&mCreateInfo, mDevice.GetVkAllocator(), &mBuffer));
+}
+
+bool BufferImpl::BindDeviceMemory(const DeviceMemory& memory, size_t offset)
+{
+ assert(!mDeviceMemory && "There is a DeviceMemory already bound!");
+ if(VkTestBool(mDevice->bindBufferMemory(mBuffer, *memory, offset)))
+ {
+ mDeviceMemory = memory;
+ mMemoryBoundOffset = offset;
+ return true;
+ }
+ return false;
+}
+
+// Handle
+namespace
+{
+BufferImpl* GetImpl(Buffer* handle)
+{
+ return static_cast< BufferImpl* >(handle->GetObject());
+}
+BufferImpl* GetImpl(const Buffer* handle)
+{
+ return static_cast< BufferImpl* >(handle->GetObject());
+}
+}
+
+Buffer Buffer::New(const LogicalDevice& device, const vk::BufferCreateInfo& info)
+{
+ auto impl = new BufferImpl(device, info);
+ if(impl->Initialise())
+ {
+ return impl;
+ }
+ return nullptr;
+}
+
+const vk::Buffer& Buffer::GetVkResource() const
+{
+ return GetImpl(this)->GetVkBuffer();
+}
+
+const vk::Buffer& Buffer::operator*() const
+{
+ return GetImpl(this)->GetVkBuffer();
+}
+
+bool Buffer::BindDeviceMemory(const DeviceMemory& memory)
+{
+ return GetImpl(this)->BindDeviceMemory(memory, 0);
+}
+
+bool Buffer::BindDeviceMemory(const DeviceMemory& memory, size_t offset)
+{
+ return GetImpl(this)->BindDeviceMemory(memory, offset);
+}
+}
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_BUFFER_H
+#define DALI_CORE_GRAPHICS_VULKAN_BUFFER_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class Buffer : public VkHandle
+{
+public:
+ Buffer(VkObject* impl = nullptr) : VkHandle(impl){}
+ using VkHandle::operator=;
+
+ static Buffer New( const class LogicalDevice& device, const vk::BufferCreateInfo& info );
+
+ const vk::Buffer& GetVkResource() const;
+ const vk::Buffer& operator*() const;
+
+ bool BindDeviceMemory( const class DeviceMemory& memory );
+
+ bool BindDeviceMemory( const class DeviceMemory& memory, size_t offset );
+
+
+
+};
+
+} // namespace Vulkan
+
+} // namespace Graphics
+
+} // namespace Dali
+
+#endif // DALI_CORE_GRAPHICS_VULKAN_BUFFER_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/command-buffer.h>
+#include <dali/graphics/vulkan/command-pool.h>
+#include <dali/graphics/vulkan/logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+using State = CommandBufferState;
+class CommandBufferImpl : public VkObject
+{
+public:
+ CommandBufferImpl(const LogicalDevice& context, const CommandPool& pool,
+ vk::CommandBufferLevel level, vk::CommandBuffer buffer)
+ : VkObject{}, mPool{pool}, mDevice{context}, mBuffer{buffer}, mLevel{level}
+ {
+ }
+
+ bool OnSafeDelete() override
+ {
+ // mind that the resources may not be released if the pool doesn't allow
+ // freeing a single command buffer! Synchronization is explicit
+ if(mPool)
+ {
+ mDevice.GetVkDevice().freeCommandBuffers(mPool.GetCommandPool(), 1, &mBuffer);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ const vk::CommandBuffer& GetVkCommandBuffer() const
+ {
+ return mBuffer;
+ }
+
+ const CommandPool& GetCommandPool() const
+ {
+ return mPool;
+ }
+
+ State GetState() const
+ {
+ return mState;
+ }
+
+ bool Begin(bool oneTimeSubmit, bool renderPassContinue, bool simultaneousUse);
+ bool End();
+ bool Free();
+ bool Reset();
+
+private:
+ CommandPool mPool;
+ LogicalDevice mDevice;
+ vk::CommandBuffer mBuffer;
+ vk::CommandBufferLevel mLevel;
+
+ // state of command buffer
+ State mState{State::UNDEFINED};
+};
+
+bool CommandBufferImpl::Begin(bool oneTimeSubmit, bool renderPassContinue, bool simultaneousUse)
+{
+ // check state
+ if(mState != State::CREATED && mState != State::UNDEFINED && mState != State::RESET)
+ {
+ VkLog("[VKCMDBUF] Invalid buffer state: %d", static_cast< int >(mState));
+ return false;
+ }
+
+ vk::CommandBufferUsageFlags flags{};
+ if(oneTimeSubmit)
+ {
+ flags |= vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
+ }
+ if(renderPassContinue)
+ {
+ flags |= vk::CommandBufferUsageFlagBits::eRenderPassContinue;
+ }
+ if(simultaneousUse)
+ {
+ flags |= vk::CommandBufferUsageFlagBits::eSimultaneousUse;
+ }
+
+ // todo implement inheritance
+ vk::CommandBufferBeginInfo info;
+ info.setFlags(flags).setPInheritanceInfo(nullptr);
+
+ if(VkTestCall(mBuffer.begin(&info)) == vk::Result::eSuccess)
+ {
+ mState = State::RECORDING;
+ return true;
+ }
+
+ return false;
+}
+
+bool CommandBufferImpl::End()
+{
+ // check state
+ if(mState != State::RECORDING)
+ {
+ VkLog("[VKCMDBUF] Invalid buffer state: %d, it must be RECORDING", static_cast< int >(mState));
+ return false;
+ }
+
+ if(VkTestCall(mBuffer.end()) == vk::Result::eSuccess)
+ {
+ mState = State::RECORDED;
+ return true;
+ }
+ return false;
+}
+
+bool CommandBufferImpl::Free()
+{
+ // todo
+ assert(false && "CommandBufferImpl::Free() unimplemented!");
+}
+
+bool CommandBufferImpl::Reset()
+{
+ if(vk::Result::eSuccess == VkTestCall(mBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources)))
+ {
+ mState = State::RESET;
+ }
+ return true;
+}
+
+// Implementation getter
+namespace
+{
+CommandBufferImpl* GetImpl(CommandBuffer* handle)
+{
+ return static_cast< CommandBufferImpl* >(handle->GetObject());
+}
+CommandBufferImpl* GetImpl(const CommandBuffer* handle)
+{
+ return static_cast< CommandBufferImpl* >(handle->GetObject());
+}
+}
+
+const vk::CommandBuffer* CommandBuffer::operator->() const
+{
+ auto& vkcmdbuf = GetImpl(this)->GetVkCommandBuffer();
+ return &vkcmdbuf;
+}
+
+std::vector< CommandBuffer > CommandBuffer::New(const CommandPool& pool, bool isPrimary, uint32_t count)
+{
+ auto vkDevice = pool.GetLogicalDevice().GetVkDevice();
+
+ std::vector< vk::CommandBuffer > buffers(count);
+
+ auto bufferLevel = isPrimary ? vk::CommandBufferLevel::ePrimary : vk::CommandBufferLevel::eSecondary;
+
+ {
+ vk::CommandBufferAllocateInfo info;
+ info.setCommandBufferCount(count).setCommandPool(pool.GetCommandPool()).setLevel(bufferLevel);
+
+ VkAssertCall(vkDevice.allocateCommandBuffers(&info, buffers.data()));
+ }
+
+ // move buffers data
+ std::vector< CommandBuffer > output(buffers.size());
+
+ for(auto&& cmdbuf : buffers)
+ {
+ output.emplace_back(new CommandBufferImpl(pool.GetLogicalDevice(), pool, bufferLevel, cmdbuf));
+ }
+ return std::move(output);
+}
+
+CommandBuffer CommandBuffer::New(const CommandPool& pool, bool isPrimary)
+{
+ // todo make more efficient implementation
+ return CommandBuffer::New(pool, isPrimary, 1)[0];
+}
+
+bool CommandBuffer::Begin(bool oneTimeSubmit, bool renderPassContinue, bool simultaneousUse)
+{
+ return GetImpl(this)->Begin(oneTimeSubmit, renderPassContinue, simultaneousUse);
+}
+
+bool CommandBuffer::End()
+{
+ return GetImpl(this)->End();
+}
+
+bool CommandBuffer::Free()
+{
+ return GetImpl(this)->Free();
+}
+
+bool CommandBuffer::Reset()
+{
+ return GetImpl(this)->Reset();
+}
+
+CommandBufferState CommandBuffer::GetState() const
+{
+ return GetImpl(this)->GetState();
+}
+
+vk::CommandBuffer CommandBuffer::GetVkBuffer() const
+{
+ return GetImpl(this)->GetVkCommandBuffer();
+}
+
+const CommandPool& CommandBuffer::GetCommandPool() const
+{
+ return GetImpl(this)->GetCommandPool();
+}
+
+std::thread::id CommandBuffer::GetThreadId() const
+{
+ return std::thread::id{};
+}
+}
+}
+}
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_COMMAND_BUFFER_H
+#define DALI_CORE_GRAPHICS_VULKAN_COMMAND_BUFFER_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+#include <thread>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+enum class CommandBufferState
+{
+ UNDEFINED,
+ CREATED,
+ RESET,
+ RECORDING,
+ RECORDED,
+ SUBMITTED
+};
+
+class CommandPool;
+class CommandBuffer : public VkHandle
+{
+public:
+ CommandBuffer(VkObject* impl = nullptr) : VkHandle{impl}
+ {
+ }
+ using VkHandle::operator=;
+
+ static std::vector< CommandBuffer > New(const CommandPool& pool, bool isPrimary, uint32_t count);
+ static CommandBuffer New(const CommandPool& pool, bool isPrimary);
+
+ vk::CommandBuffer GetVkBuffer() const;
+ const CommandPool& GetCommandPool() const;
+ std::thread::id GetThreadId() const;
+
+ CommandBufferState GetCommandBufferState() const;
+
+ // operator -> allows to record commands directly into Vulkan command buffer
+ const vk::CommandBuffer* operator->() const;
+
+ bool Begin(bool oneTimeSubmit, bool renderPassContinue = false, bool simultaneousUse = false);
+ bool End();
+ bool Free();
+ bool Reset();
+
+ CommandBufferState GetState() const;
+};
+}
+}
+}
+
+#endif // DALI_CORE_GRAPHICS_VULKAN_COMMAND_BUFFER_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/command-pool.h>
+#include <dali/graphics/vulkan/physical-device.h>
+#include <dali/graphics/vulkan/logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+
+class CommandPoolImpl : public VkObject
+{
+public:
+ CommandPoolImpl(const LogicalDevice& device, QueueType type, bool isExclusive, bool createTransient,
+ bool createResetCommandBuffer)
+ : VkObject{},
+ mDevice{ device }, mExclusive{ isExclusive },
+ mResetFlag{ createResetCommandBuffer }, mTransientFlag{ createTransient },
+ mQueueType{ type }
+ {
+ }
+
+ virtual ~CommandPoolImpl() {};
+
+ bool Initialise();
+
+ const LogicalDevice& GetLogicalDevice() const
+ {
+ return mDevice;
+ }
+
+ // vk objects getters
+public:
+
+ const vk::CommandPool GetCommandPool() const
+ {
+ return mCommandPool;
+ }
+
+ const vk::CommandPoolCreateInfo& GetCommandPoolCreateInfo() const
+ {
+ return mCreateInfo;
+ }
+
+ bool IsExclusive() const
+ {
+ return mExclusive;
+ }
+
+ bool IsTransient() const
+ {
+ return mTransientFlag;
+ }
+
+ bool IsResetFlag() const
+ {
+ return mResetFlag;
+ }
+
+ QueueType GetQueueType() const
+ {
+ return mQueueType;
+ }
+
+ std::vector< CommandBuffer > AllocateCommandBuffers(uint32_t count, bool primary);
+
+private:
+
+ LogicalDevice mDevice { nullptr };
+
+ // vulkan specific
+ vk::CommandPool mCommandPool{nullptr};
+ vk::CommandPoolCreateInfo mCreateInfo{};
+
+ std::thread::id mThreadId; // used if exclusive
+
+ // queue properties
+ bool mExclusive{false};
+ bool mResetFlag{false};
+ bool mTransientFlag{false};
+
+ QueueType mQueueType;
+};
+
+bool CommandPoolImpl::Initialise()
+{
+ auto vkDevice = mDevice.GetVkDevice();
+ auto phDevice = mDevice.GetPhysicalDevice();
+
+ vk::CommandPoolCreateFlags flags{};
+ if( mResetFlag )
+ {
+ flags |= vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
+ }
+ if( mTransientFlag )
+ {
+ flags |= vk::CommandPoolCreateFlagBits::eTransient;
+ }
+
+ vk::CommandPoolCreateInfo info;
+
+ info.setQueueFamilyIndex( phDevice.GetQueueFamilyIndex( mQueueType) );
+ info.flags = flags;
+ mCreateInfo = info;
+
+ VkAssertCall( vkDevice.createCommandPool( &info, mDevice.GetVkAllocator(), &mCommandPool ) );
+
+ VkLog("[VULKAN] CommandPoolImpl::Initialise() created!");
+
+ return true;
+}
+
+std::vector< CommandBuffer > CommandPoolImpl::AllocateCommandBuffers(uint32_t count, bool primary)
+{
+ return std::move(CommandBuffer::New( CommandPool(this), primary, count ));
+}
+
+CommandPool CommandPool::New(const LogicalDevice& device, QueueType type, bool isExclusive,
+ bool createTransient, bool createResetCommandBuffer)
+{
+ auto impl = new CommandPoolImpl(device, type, isExclusive, createTransient, createResetCommandBuffer);
+ CommandPool retval( impl );
+ if(!impl->Initialise())
+ {
+ retval = nullptr;
+ }
+ return retval;
+}
+
+
+// Implementation getter
+namespace
+{
+CommandPoolImpl* GetImpl( CommandPool* pool )
+{
+ return static_cast<CommandPoolImpl*>(pool->GetObject());
+}
+CommandPoolImpl* GetImpl( const CommandPool* pool )
+{
+ return static_cast<CommandPoolImpl*>(pool->GetObject());
+}
+}
+bool CommandPool::Initialise()
+{
+ return GetImpl(this)->Initialise();
+}
+
+const vk::CommandPool CommandPool::GetCommandPool() const
+{
+ return GetImpl(this)->GetCommandPool();
+}
+
+const vk::CommandPoolCreateInfo& CommandPool::GetVkCommandPoolCreateInfo() const
+{
+ return GetImpl(this)->GetCommandPoolCreateInfo();
+}
+
+const LogicalDevice& CommandPool::GetLogicalDevice() const
+{
+ return GetImpl(this)->GetLogicalDevice();
+}
+
+std::thread::id CommandPool::GetThreadId() const
+{
+ //return GetImplementation<CommandPoolImpl>(this)->mThreadId;
+ return std::thread::id();
+}
+
+void CommandPool::ThreadAttach()
+{
+
+}
+
+void CommandPool::ThreadDetach()
+{
+
+}
+
+
+std::vector< CommandBuffer > CommandPool::AllocateCommandBuffers(uint32_t count, bool primary)
+{
+ return std::move(GetImpl(this)->AllocateCommandBuffers( count, primary ));
+}
+
+CommandBuffer CommandPool::AllocateCommandBuffer(bool primary)
+{
+ return GetImpl(this)->AllocateCommandBuffers( 1, primary )[0];
+}
+
+
+}
+}
+}
--- /dev/null
+#ifndef DALI_CORE_VULKAN_COMMAND_POOL_H
+#define DALI_CORE_VULKAN_COMMAND_POOL_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/command-buffer.h>
+#include <dali/graphics/vulkan/common.h>
+#include <thread>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+class LogicalDevice;
+
+//using VulkanCommandBufferArray = std::vector< VulkanCommandBuffer >;
+
+class CommandPool : public VkHandle
+{
+public:
+ CommandPool(VkObject* impl = nullptr) : VkHandle{impl}
+ {
+ }
+ using VkHandle::operator=;
+
+ static CommandPool New(const LogicalDevice& context, QueueType type, bool isExclusive,
+ bool createTransient, bool createResetCommandBuffer);
+
+ bool Initialise();
+
+ // attaching to thread will make sure that any attempt of using pool on the
+ // wrong thread will assert
+ void ThreadAttach();
+ void ThreadDetach();
+
+ const vk::CommandPool GetCommandPool() const;
+ const LogicalDevice& GetLogicalDevice() const;
+ const vk::CommandPoolCreateInfo& GetVkCommandPoolCreateInfo() const;
+ std::thread::id GetThreadId() const;
+
+ std::vector< CommandBuffer > AllocateCommandBuffers(uint32_t count, bool primary);
+ CommandBuffer AllocateCommandBuffer(bool primary);
+};
+}
+}
+}
+
+#endif //DALI_CORE_VULKANCOMMANDPOOL_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/command-queue.h>
+#include <dali/graphics/vulkan/logical-device.h>
+#include <dali/graphics/vulkan/physical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+class QueueImpl : public VkObject
+{
+public:
+ QueueImpl(const LogicalDevice& device, QueueType type, uint32_t queueIndex)
+ : VkObject{}, mDevice{device}, mType{type}, mQueue{nullptr}, mQueueIndex{queueIndex}
+ {
+ }
+
+ bool Initialise()
+ {
+ auto phDevice = mDevice.GetPhysicalDevice();
+ auto vkDevice = mDevice.GetVkDevice();
+
+ uint32_t familyIndex = static_cast< uint32_t >(phDevice.GetQueueFamilyIndex(mType));
+ vkDevice.getQueue(familyIndex, mQueueIndex, &mQueue);
+ return true;
+ }
+
+ bool Submit(const std::vector< CommandBuffer >& buffers, vk::Fence fence = nullptr)
+ {
+ return Submit(buffers.data(), static_cast< uint32_t >(buffers.size()), nullptr, 0, nullptr, 0, nullptr, fence);
+ }
+
+ bool Submit(const CommandBuffer* pBuffers, const uint32_t bufferCount,
+ const vk::Semaphore* pWaitSemaphores, const uint32_t waitSemaphoreCount,
+ const vk::Semaphore* pSignalSemaphores, const uint32_t signalSemaphoreCount,
+ const vk::PipelineStageFlags* pWaitDstStageFlags, vk::Fence fence)
+ {
+ // todo make temporary copy more efficient
+ auto vkBuffers = std::vector< vk::CommandBuffer >(bufferCount);
+ for(uint32_t index = 0; index < bufferCount; ++index)
+ {
+ vkBuffers[index] = pBuffers[index].GetVkBuffer();
+ }
+
+ if(fence)
+ {
+ mDevice.GetVkDevice().resetFences(1, &fence);
+ }
+
+ vk::SubmitInfo info;
+ info.setCommandBufferCount(bufferCount)
+ .setPCommandBuffers(vkBuffers.data())
+ .setWaitSemaphoreCount(waitSemaphoreCount)
+ .setPWaitSemaphores(pWaitSemaphores)
+ .setSignalSemaphoreCount(signalSemaphoreCount)
+ .setPSignalSemaphores(pSignalSemaphores)
+ .setPWaitDstStageMask(pWaitDstStageFlags);
+
+ if(VkTestCall(mQueue.submit(1, &info, fence)) != vk::Result::eSuccess)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ void WaitIdle() const
+ {
+ mQueue.waitIdle();
+ }
+
+ LogicalDevice mDevice;
+ QueueType mType;
+ vk::Queue mQueue;
+ uint32_t mQueueIndex;
+};
+
+namespace
+{
+QueueImpl* GetImpl(const CommandQueue* queue)
+{
+ return static_cast< QueueImpl* >(queue->GetObject());
+}
+QueueImpl* GetImpl(CommandQueue* queue)
+{
+ return static_cast< QueueImpl* >(queue->GetObject());
+}
+}
+
+CommandQueue CommandQueue::Get(const LogicalDevice& device, QueueType type, uint32_t queueIndex)
+{
+ auto impl = new QueueImpl(device, type, queueIndex);
+ impl->Initialise();
+ CommandQueue retval(impl);
+ return retval;
+}
+
+vk::Queue CommandQueue::GetVkQueue() const
+{
+ return GetImpl(this)->mQueue;
+}
+
+uint32_t CommandQueue::GetIndex() const
+{
+ return GetImpl(this)->mQueueIndex;
+}
+
+QueueType CommandQueue::GetType() const
+{
+ return GetImpl(this)->mType;
+}
+
+bool CommandQueue::Submit(const std::vector< CommandBuffer >& buffers, vk::Fence fence)
+{
+ return GetImpl(this)->Submit(buffers, fence);
+}
+
+bool CommandQueue::Submit(const CommandBuffer* buffers, uint32_t count, vk::Fence fence)
+{
+ return GetImpl(this)->Submit(buffers, count, nullptr, 0, nullptr, 0, nullptr, fence);
+}
+
+bool CommandQueue::Submit(const CommandBuffer* pBuffers, const uint32_t bufferCount,
+ const vk::Semaphore* pWaitSemaphores, const uint32_t waitSemaphoreCount,
+ const vk::Semaphore* pSignalSemaphores, const uint32_t signalSemaphoreCount,
+ const vk::PipelineStageFlags* pWaitDstStageFlags, vk::Fence fence) const
+{
+ return GetImpl(this)->Submit(pBuffers, bufferCount, pWaitSemaphores, waitSemaphoreCount,
+ pSignalSemaphores, signalSemaphoreCount, pWaitDstStageFlags, fence);
+}
+
+void CommandQueue::WaitIdle() const
+{
+ GetImpl(this)->WaitIdle();
+}
+}
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_COMMAND_QUEUE_H
+#define DALI_CORE_GRAPHICS_VULKAN_COMMAND_QUEUE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+class CommandBuffer;
+class LogicalDevice;
+
+class CommandQueue : public VkHandle
+{
+public:
+ CommandQueue(VkObject* impl = nullptr) : VkHandle{impl}
+ {
+ }
+ using VkHandle::operator=;
+
+ static CommandQueue Get(const LogicalDevice& device, QueueType type, uint32_t queueIndex);
+
+ vk::Queue GetVkQueue() const;
+ uint32_t GetIndex() const;
+ QueueType GetType() const;
+
+ bool Submit(const CommandBuffer* buffers, uint32_t count, vk::Fence fence);
+ bool Submit(const std::vector< CommandBuffer >& buffers, vk::Fence fence);
+ bool Submit(const CommandBuffer* pBuffers, const uint32_t bufferCount,
+ const vk::Semaphore* pWaitSemaphores, const uint32_t waitSemaphoreCount,
+ const vk::Semaphore* pSignalSemaphores, const uint32_t signalSemaphoreCount,
+ const vk::PipelineStageFlags* pWaitDstStageFlags, vk::Fence fence) const;
+
+ void WaitIdle() const;
+};
+}
+}
+}
+
+#endif // DALI_CORE_GRAPHICS_VULKAN_COMMAND_QUEUE_H
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_COMMON_H
+#define DALI_CORE_GRAPHICS_VULKAN_COMMON_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <vulkan/vulkan.hpp>
+
+#include <cassert>
+#include <cinttypes>
+#include <memory>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+void VkLog(const char* format, ...);
+
+#define OBJECT_HANDLE(TYPE)\
+public:\
+ TYPE( VkObject* object = nullptr ) : VkHandle{ object }{}\
+ using VkHandle::operator=;
+
+
+#define VkAssert(var, message) \
+ { \
+ if(var.result != vk::Result::eSuccess) \
+ { \
+ Dali::Graphics::Vulkan::VkLog("[Assert] %s", message); \
+ assert(var.result == vk::Result::eSuccess); \
+ } \
+ }
+
+#define VkAssertCall(call) \
+ { \
+ const auto& _result = call; \
+ if(_result != vk::Result::eSuccess) \
+ { \
+ Dali::Graphics::Vulkan::VkLog("[VkAssertCall] %s:%d: %s", __FILE__, __LINE__, #call); \
+ assert(_result == vk::Result::eSuccess); \
+ } \
+ }
+
+#define VkAssertCallMsg(call, msg) \
+ { \
+ auto _result = call; \
+ if(_result != vk::Result::eSuccess) \
+ { \
+ Dali::Graphics::Vulkan::VkLog("[VkAssertCall] %s:%d: %s, %s", __FILE__, __LINE__, #call, msg); \
+ assert(_result == vk::Result::eSuccess); \
+ } \
+ }
+
+inline vk::Result VkTestCallFn(vk::Result result, const char* file, const char* call, int line)
+{
+ if(result != vk::Result::eSuccess)
+ {
+ Dali::Graphics::Vulkan::VkLog("[VkTestCall] %s:%d: %s -> Result = %d", file, line, call, static_cast< int >(result));
+ }
+ return result;
+}
+
+#define VkTestCall(call) VkTestCallFn(call, __FILE__, #call, __LINE__)
+#define VkTestBool(call) (vk::Result::eSuccess == VkTestCallFn(call, __FILE__, #call, __LINE__))
+}
+
+// helper template to create relation between flags and bits
+template< typename BitType, typename FlagType = uint32_t >
+struct BitFlags
+{
+ BitFlags() = default;
+
+ BitFlags(FlagType f) : flags(f)
+ {
+ }
+
+ BitFlags(const BitType& bit)
+ {
+ flags = static_cast< FlagType >(bit);
+ }
+
+ operator FlagType()
+ {
+ return flags;
+ }
+
+ bool operator==(FlagType srcFlags) const
+ {
+ return srcFlags == flags;
+ }
+
+ bool operator!=(const FlagType& srcFlags) const
+ {
+ return srcFlags != flags;
+ }
+
+ BitFlags operator|(const BitType& bit)
+ {
+ return BitFlags(flags | static_cast< FlagType >(bit));
+ }
+
+ BitFlags& operator|=(const BitType& bit)
+ {
+ flags |= static_cast< FlagType >(bit);
+ return *this;
+ }
+
+ BitFlags operator&(const BitFlags& rhs) const
+ {
+ return FlagType{(rhs.flags & flags)};
+ }
+
+ BitFlags operator&(unsigned int rhs) const
+ {
+ return BitFlags{(rhs & flags)};
+ }
+
+ FlagType flags{0};
+};
+
+using ExtensionNameList = std::vector< const char* >;
+using LayerNameList = std::vector< const char* >;
+
+// common for adaptor
+enum class ValidationLayerBit2
+{
+ NONE = 0,
+ SCREENSHOT = (1 << 0),
+ PARAMETER_VALIDATION = (1 << 1),
+ VKTRACE = (1 << 2),
+ MONITOR = (1 << 3),
+ SWAPCHAIN = (1 << 4),
+ THREADING = (1 << 5),
+ API_DUMP = (1 << 6),
+ OBJECT_TRACKER = (1 << 7),
+ CORE_VALIDATION = (1 << 8),
+ UNIQUE_OBJECTS = (1 << 9),
+ STANDARD_VALIDATION = (1 << 10),
+ ALL = 0xFFFF
+};
+
+enum class ValidationChannelBit
+{
+ NONE = 0,
+ INFORMATION = (1 << 0),
+ WARNING = (1 << 1),
+ PERFORMANCE_WARNING = (1 << 2),
+ ERROR = (1 << 3),
+ DEBUG = (1 << 4),
+ ALL = 0xFF
+};
+
+using ValidationLayerFlags2 = BitFlags< ValidationLayerBit2 >;
+using ValidationChannelFlags = BitFlags< ValidationChannelBit >;
+
+enum class PhysicalDeviceBit
+{
+ // physical device type
+ ANY = 0,
+ DISCRETE = (1 << 0),
+ INTEGRATED = (1 << 1)
+};
+
+using PhysicalDeviceFlags = BitFlags< PhysicalDeviceBit >;
+
+/// -----------------------------------------------------
+// vulkan only some sort of managed objects support
+//
+class VkObject
+{
+public:
+ VkObject() = default;
+ virtual ~VkObject() = default;
+
+ uint32_t RetainRef()
+ {
+ return ++mObjectRefCount;
+ }
+
+ uint32_t ReleaseRef()
+ {
+ return --mObjectRefCount;
+ }
+
+ uint32_t GetRefCount()
+ {
+ return mObjectRefCount;
+ }
+
+ // handles releasing of vulkan object before being deleted
+ // or moved to discard queue
+ virtual bool OnSafeDelete()
+ {
+ return true;
+ }
+
+private:
+ uint32_t mObjectRefCount{0};
+};
+
+template< typename OBJECT >
+class VkHandleBase
+{
+public:
+ VkHandleBase() = default;
+ VkHandleBase(OBJECT* ptr)
+ {
+ mObject = ptr;
+ if(mObject)
+ {
+ static_cast< VkObject * >(mObject)->RetainRef();
+ }
+ }
+
+ VkHandleBase(const VkHandleBase& handle)
+ {
+ if(handle.mObject)
+ {
+ static_cast< VkObject * >(handle.mObject)->RetainRef();
+ }
+
+ mObject = handle.mObject;
+ }
+
+ virtual ~VkHandleBase()
+ {
+ if(mObject)
+ {
+ static_cast< VkObject* >(mObject)->ReleaseRef();
+ TrySafeDelete();
+ }
+ }
+
+ VkHandleBase& operator=(OBJECT* ptr)
+ {
+ if(mObject == ptr)
+ {
+ return *this;
+ }
+ if(mObject)
+ {
+ static_cast< VkObject* >(mObject)->ReleaseRef();
+ TrySafeDelete();
+ }
+ if(ptr)
+ {
+ static_cast< VkObject * >(ptr)->RetainRef();
+ }
+ mObject = ptr;
+ return *this;
+ }
+
+ VkHandleBase& operator=(const VkHandleBase& handle)
+ {
+ if(handle.mObject == mObject)
+ {
+ return *this;
+ }
+ if(mObject)
+ {
+ static_cast< VkObject* >(mObject)->ReleaseRef();
+ TrySafeDelete();
+ }
+ mObject = handle.mObject;
+ if(mObject)
+ {
+ static_cast< VkObject * >(mObject)->RetainRef();
+ }
+ return *this;
+ }
+
+ OBJECT* GetObject() const
+ {
+ return mObject;
+ }
+
+ operator bool() const
+ {
+ return mObject != nullptr;
+ }
+
+ bool operator!() const
+ {
+ return mObject == nullptr;
+ }
+
+ void Reset()
+ {
+ if(mObject)
+ {
+ static_cast< VkObject * >(mObject)->ReleaseRef();
+ }
+ TrySafeDelete();
+ mObject = nullptr;
+ }
+
+ bool TrySafeDelete()
+ {
+ if(!static_cast< VkObject* >(mObject)->GetRefCount())
+ {
+ if(static_cast< VkObject* >(mObject)->OnSafeDelete())
+ {
+ delete mObject;
+ }
+ }
+ // todo: deletion didn't go well, should be asserted?
+ return false;
+ }
+
+ template< typename T >
+ T Cast()
+ {
+ return T(dynamic_cast< OBJECT* >(mObject));
+ }
+
+protected:
+ OBJECT* mObject{nullptr};
+};
+
+using VkHandle = VkHandleBase< VkObject >;
+
+enum class QueueType : uint32_t
+{
+ GRAPHICS = 0u,
+ COMPUTE = 1u,
+ TRANSFER = 2u,
+ SPARSE_BINDING = 3u,
+ PRESENT = 4u,
+ END
+};
+}
+}
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_COMMON_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+#include <dali/graphics/vulkan/device-memory.h>
+#include <dali/graphics/vulkan/logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class DeviceMemoryImpl : public VkObject
+{
+public:
+ DeviceMemoryImpl(const LogicalDevice& device, const vk::MemoryAllocateInfo& allocateInfo);
+
+ bool Initialise();
+
+ virtual bool OnSafeDelete();
+
+ const LogicalDevice& GetLogicalDevice() const
+ {
+ return mDevice;
+ }
+
+ const vk::DeviceMemory& GetVkDeviceMemory() const
+ {
+ return mMemory;
+ }
+
+ size_t GetSize() const
+ {
+ return mSize;
+ }
+
+ void* Map(size_t offset, size_t range);
+
+ void Unmap();
+
+ void Flush(size_t offset, size_t range);
+
+private:
+ LogicalDevice mDevice{nullptr};
+ vk::MemoryAllocateInfo mAllocateInfo;
+ vk::DeviceMemory mMemory{nullptr};
+ size_t mSize{0u};
+ void* mMappedPtr{nullptr};
+};
+
+// Implementation
+
+DeviceMemoryImpl::DeviceMemoryImpl(const LogicalDevice& device, const vk::MemoryAllocateInfo& allocateInfo)
+: mDevice(device), mAllocateInfo(allocateInfo), mMemory(nullptr), mSize(0u)
+{
+}
+
+bool DeviceMemoryImpl::Initialise()
+{
+ auto vkDevice = mDevice.GetVkDevice();
+ auto vkAllocator = mDevice.GetVkAllocator();
+
+ VkAssertCall(vkDevice.allocateMemory(&mAllocateInfo, vkAllocator, &mMemory));
+
+ mSize = mAllocateInfo.allocationSize;
+ return true;
+}
+
+bool DeviceMemoryImpl::OnSafeDelete()
+{
+ if(mMemory)
+ {
+ mDevice.GetVkDevice().freeMemory(mMemory, mDevice.GetVkAllocator());
+ return true;
+ }
+ return false;
+}
+
+void* DeviceMemoryImpl::Map(size_t offset, size_t range)
+{
+ assert(mMappedPtr == nullptr && "Device memory must not be previously mapped!");
+ void *ptr = nullptr;
+ if (VkTestCall(mDevice.GetVkDevice()
+ .mapMemory(mMemory, offset, range, vk::MemoryMapFlags(), &ptr)) !=
+ vk::Result::eSuccess)
+ {
+ return nullptr;
+ }
+ mMappedPtr = ptr;
+ return ptr;
+}
+
+void DeviceMemoryImpl::Unmap()
+{
+ assert(mMappedPtr != nullptr && "Device memory must be mapped!");
+ mDevice.GetVkDevice().unmapMemory(mMemory);
+ mMappedPtr = nullptr;
+}
+
+void DeviceMemoryImpl::Flush(size_t offset, size_t size)
+{
+ vk::MappedMemoryRange range;
+ range.setOffset(offset).setMemory(mMemory).setSize(size);
+ mDevice.GetVkDevice().flushMappedMemoryRanges(1, &range);
+}
+
+// Handle
+
+namespace
+{
+DeviceMemoryImpl* GetImpl(DeviceMemory* handle)
+{
+ return static_cast< DeviceMemoryImpl* >(handle->GetObject());
+}
+
+DeviceMemoryImpl* GetImpl(const DeviceMemory* handle)
+{
+ return static_cast< DeviceMemoryImpl* >(handle->GetObject());
+}
+}
+
+DeviceMemory DeviceMemory::New(class LogicalDevice& device, const vk::MemoryAllocateInfo& allocateInfo)
+{
+ auto impl = new DeviceMemoryImpl(device, allocateInfo);
+ if(impl->Initialise())
+ {
+ return impl;
+ }
+ return nullptr;
+}
+
+const LogicalDevice& DeviceMemory::GetLogicalDevice() const
+{
+ return GetImpl(this)->GetLogicalDevice();
+}
+
+const vk::DeviceMemory& DeviceMemory::GetVkDeviceMemory() const
+{
+ return GetImpl(this)->GetVkDeviceMemory();
+}
+
+const vk::DeviceMemory& DeviceMemory::operator*() const
+{
+ return GetImpl(this)->GetVkDeviceMemory();
+}
+
+size_t DeviceMemory::GetSize() const
+{
+ return GetImpl(this)->GetSize();
+}
+
+void* DeviceMemory::Map(size_t offset, size_t range)
+{
+ return GetImpl(this)->Map(offset, range);
+}
+
+void DeviceMemory::Unmap()
+{
+ GetImpl(this)->Unmap();
+}
+
+void DeviceMemory::Flush(size_t offset, size_t range)
+{
+ GetImpl(this)->Flush(offset, range);
+}
+
+void DeviceMemory::Flush()
+{
+ GetImpl(this)->Flush(0, VK_WHOLE_SIZE);
+}
+
+} // Vulkan
+} // Graphics
+} // Dali
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_DEVICE_MEMORY_H
+#define DALI_CORE_GRAPHICS_VULKAN_DEVICE_MEMORY_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class DeviceMemory : public VkHandle
+{
+public:
+ DeviceMemory(VkObject* object = nullptr) : VkHandle{object}
+ {
+ }
+
+ using VkHandle::operator=;
+
+ /**
+ * New DeviceMemory associated with logical device
+ * @param device
+ * @param allocateInfo
+ * @return
+ */
+ static DeviceMemory New(class LogicalDevice &device, const vk::MemoryAllocateInfo &allocateInfo);
+
+ /**
+ * Map memory ( only if host visible )
+ * @param offset
+ * @param range
+ * @return
+ */
+ void *Map(size_t offset, size_t range);
+
+ /**
+ * Unmap previously mapped memory
+ */
+ void Unmap();
+
+ /**
+ * Flush device memory in selected range
+ * @param offset
+ * @param range
+ */
+ void Flush(size_t offset, size_t range);
+
+ /**
+ * Flush entire block allocated as device memory
+ */
+ void Flush();
+
+ const class LogicalDevice &GetLogicalDevice() const;
+ const vk::DeviceMemory & GetVkDeviceMemory() const;
+ const vk::DeviceMemory &operator*() const;
+ size_t GetSize() const;
+};
+}
+}
+}
+
+#endif // DALI_CORE_GRAPHICS_VULKAN_DEVICE_MEMORY_H
--- /dev/null
+#ifndef DALI_GRAPHICS_VULKAN_FRAME_STACK
+#define DALI_GRAPHICS_VULKAN_FRAME_STACK
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <cstdint>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+using Frame = char*;
+
+/**
+ * Simple stack frame-based fixed size allocator ( single sided )
+ */
+class Stack
+{
+public:
+
+ Stack( uint32_t capacityInBytes )
+ {
+ mData = new char[capacityInBytes];
+ mCurrentPtr = mData;
+ mCapacity = capacityInBytes;
+ mRecentFrame = nullptr;
+ }
+
+ ~Stack()
+ {
+ delete [] mCurrentPtr;
+ }
+
+ Frame Mark()
+ {
+ mRecentFrame = mCurrentPtr;
+ return mCurrentPtr;
+ }
+
+ Frame Rollback( Frame frame = nullptr )
+ {
+ if( !frame )
+ {
+ if( mRecentFrame )
+ {
+ mCurrentPtr = mRecentFrame;
+ mRecentFrame = nullptr;
+ }
+ else
+ {
+ mCurrentPtr = mData;
+ }
+ }
+ return mCurrentPtr;
+ }
+
+ void RollbackAll()
+ {
+ mCurrentPtr = mData;
+ }
+
+ template <typename T>
+ T* Alloc( uint32_t count = 1 )
+ {
+ uintptr_t alignment = alignof(T)-(reinterpret_cast<uintptr_t>(mCurrentPtr)%alignof(T));
+ auto result = reinterpret_cast<T*>(mCurrentPtr + alignment);
+ if( result >= reinterpret_cast<T*>( mData + mCapacity ) )
+ {
+ return nullptr;
+ }
+ mCurrentPtr += sizeof(T) * count;
+ return result;
+ }
+
+ template <typename T, typename... Args>
+ T* AllocNew( Args&&... args )
+ {
+ T* ptr = Alloc<T>(1);
+ if(!ptr)
+ {
+ return nullptr;
+ }
+ return new(ptr)T(args...);
+ }
+
+ template <typename T, typename... Args>
+ T& AllocNewRef( Args&&... args )
+ {
+ T* ptr = Alloc<T>(1);
+ return *(new(ptr)T(args...));
+ }
+
+private:
+
+ char* mData { nullptr };
+ char* mCurrentPtr { nullptr };
+ char* mRecentFrame { nullptr };
+ uint32_t mCapacity { 0u };
+};
+
+} // namespace Vulkan
+} // namespace Graphics
+} // namespace Dali
+
+
+#endif //DALI_GRAPHICS_VULKAN_FRAME_STACK
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include "framebuffer.h"
+#include <dali/graphics/vulkan/logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+namespace Internal
+{
+class Framebuffer : public VkObject
+{
+public:
+ Framebuffer() = delete;
+
+ Framebuffer(const LogicalDevice &device, const vk::FramebufferCreateInfo &info)
+ : VkObject{}, mDevice{device}, mCreateInfo(info)
+ {
+ }
+
+ virtual ~Framebuffer() = default;
+
+ bool Initialise();
+
+ const vk::Framebuffer &GetVkObject() const
+ {
+ return mFramebuffer;
+ }
+
+ virtual bool OnSafeDelete() override
+ {
+ if( mFramebuffer )
+ {
+ mDevice->destroyFramebuffer(mFramebuffer, mDevice.GetVkAllocator());
+ return true;
+ }
+ return false;
+ }
+
+private:
+ LogicalDevice mDevice;
+
+ vk::FramebufferCreateInfo mCreateInfo {};
+ vk::Framebuffer mFramebuffer {nullptr};
+
+
+};
+
+bool Framebuffer::Initialise()
+{
+ return VkTestBool(mDevice->createFramebuffer(&mCreateInfo, mDevice.GetVkAllocator(), &mFramebuffer));
+}
+
+}
+
+namespace
+{
+Internal::Framebuffer* GetImpl( const Framebuffer* handle )
+{
+ return static_cast<Internal::Framebuffer*>(handle->GetObject());
+}
+
+}
+
+Framebuffer Framebuffer::New(const class LogicalDevice& device, const vk::FramebufferCreateInfo& info)
+{
+ auto impl = new Internal::Framebuffer(device, info);
+ if(impl->Initialise())
+ {
+ return impl;
+ }
+ return nullptr;
+}
+
+const vk::Framebuffer& Framebuffer::operator*() const
+{
+ return GetImpl(this)->GetVkObject();
+}
+
+}
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_FRAMEBUFFER_H
+#define DALI_CORE_GRAPHICS_VULKAN_FRAMEBUFFER_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class Framebuffer : public VkHandle
+{
+public:
+ OBJECT_HANDLE(Framebuffer)
+
+ const vk::Framebuffer& operator*() const;
+
+ static Framebuffer New( const class LogicalDevice& device, const vk::FramebufferCreateInfo& info );
+
+};
+
+}
+}
+}
+
+
+
+#endif //DALI_CORE_FRAMEBUFFER_H
--- /dev/null
+//
+// Created by adam.b on 03/05/17.
+//
+
+#include <dali/graphics/vulkan/image-view.h>
+#include <dali/graphics/vulkan/image.h>
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+namespace Internal
+{
+class ImageView : public VkObject
+{
+public:
+ ImageView() = delete;
+ ImageView( const Image& image, const vk::ImageViewCreateInfo& info );
+
+private:
+
+ Image mImage { nullptr };
+ vk::ImageViewCreateInfo mCreateInfo { };
+};
+
+ImageView::ImageView( const Image& image, const vk::ImageViewCreateInfo& info )
+: VkObject()
+{
+
+}
+
+}
+
+} // namespace Vulkan
+} // namespace Graphics
+} // namespace Dali
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#ifndef DALI_CORE_GRAPHICS_VULKAN_IMAGEVIEW_H
+#define DALI_CORE_GRAPHICS_VULKAN_IMAGEVIEW_H
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class ImageView : public VkHandle
+{
+ OBJECT_HANDLE(ImageView)
+
+};
+
+} // namespace Vulkan
+} // namespace Graphics
+} // namespace Dali
+
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_IMAGEVIEW_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/device-memory.h>
+#include <dali/graphics/vulkan/image.h>
+#include <dali/graphics/vulkan/logical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class ImageImpl : public VkObject
+{
+public:
+ ImageImpl(const LogicalDevice& device, const vk::ImageCreateInfo& createInfo);
+
+ /**
+ * Initialises new image
+ * @return
+ */
+ bool Initialise();
+
+ /**
+ * Creates VkImageMemoryBarrier instance in order to change image layout
+ * @param newLayout
+ * @param srcAccess
+ * @param dstAccess
+ * @return
+ */
+ vk::ImageMemoryBarrier CreateLayoutBarrier(vk::ImageLayout newLayout, vk::AccessFlags srcAccess,
+ vk::AccessFlags dstAccess);
+
+ const vk::Image& GetVkImage() const
+ {
+ return mImage;
+ }
+
+ bool BindDeviceMemory(const DeviceMemory& memory, size_t offset);
+
+ const vk::ImageCreateInfo& GetImageCreateInfo() const
+ {
+ return mCreateInfo;
+ }
+
+ const vk::ImageLayout& GetLayout() const
+ {
+ return mLayout;
+ }
+
+ void SetLayout(vk::ImageLayout layout )
+ {
+ mLayout = layout;
+ }
+
+private:
+ LogicalDevice mDevice{nullptr};
+ vk::ImageCreateInfo mCreateInfo{};
+ vk::Image mImage{nullptr};
+ vk::ImageLayout mLayout;
+
+ DeviceMemory mDeviceMemory{nullptr}; // todo future higher-level wrapper on device memory
+ size_t mBoundMemoryOffset{0u};
+};
+
+// Implementation
+
+ImageImpl::ImageImpl(const LogicalDevice& device, const vk::ImageCreateInfo& createInfo)
+: mDevice(device), mCreateInfo(createInfo)
+{
+}
+
+bool ImageImpl::Initialise()
+{
+ mLayout = mCreateInfo.initialLayout;
+ return VkTestBool(mDevice->createImage(&mCreateInfo, mDevice.GetVkAllocator(), &mImage));
+}
+
+bool ImageImpl::BindDeviceMemory(const DeviceMemory& memory, size_t offset)
+{
+ assert(!mDeviceMemory && "DeviceMemory is already set on the Image!");
+ if( VkTestBool(mDevice->bindImageMemory(mImage, memory.GetVkDeviceMemory(), offset)) )
+ {
+ mDeviceMemory = memory;
+ mBoundMemoryOffset = offset;
+ return true;
+ }
+ return false;
+}
+
+vk::ImageMemoryBarrier ImageImpl::CreateLayoutBarrier(vk::ImageLayout newLayout,
+ vk::AccessFlags srcAccess, vk::AccessFlags dstAccess)
+{
+ return vk::ImageMemoryBarrier{};
+}
+
+// Handle
+namespace
+{
+ImageImpl* GetImpl(Image* handle)
+{
+ return static_cast< ImageImpl* >(handle->GetObject());
+}
+ImageImpl* GetImpl(const Image* handle)
+{
+ return static_cast< ImageImpl* >(handle->GetObject());
+}
+}
+
+Image Image::New(const LogicalDevice& device, const vk::ImageCreateInfo& createInfo)
+{
+ auto impl = new ImageImpl(device, createInfo);
+ if(impl->Initialise())
+ {
+ return impl;
+ }
+ return nullptr;
+}
+
+const vk::Image& Image::GetVkResource() const
+{
+ return GetImpl(this)->GetVkImage();
+}
+
+const vk::Image& Image::operator*() const
+{
+ return GetImpl(this)->GetVkImage();
+}
+
+bool Image::BindDeviceMemory(const DeviceMemory& memory)
+{
+ return GetImpl(this)->BindDeviceMemory(memory, 0);
+}
+
+bool Image::BindDeviceMemory(const DeviceMemory& memory, size_t offset)
+{
+ return GetImpl(this)->BindDeviceMemory(memory, offset);
+}
+
+vk::ImageMemoryBarrier Image::GetLayoutChangeBarrier(vk::ImageLayout newLayout,
+ vk::AccessFlags srcAccess, vk::AccessFlags dstAccess,
+ vk::ImageAspectFlags imageAspect) const
+{
+ auto& info = GetImpl(this)->GetImageCreateInfo();
+
+ vk::ImageSubresourceRange subresourceRange;
+ subresourceRange.setBaseArrayLayer(0)
+ .setLayerCount(info.arrayLayers)
+ .setAspectMask(imageAspect)
+ .setBaseArrayLayer(0)
+ .setLevelCount(info.mipLevels)
+ .setBaseMipLevel(0);
+
+ vk::ImageMemoryBarrier barrier;
+ barrier.setNewLayout(newLayout)
+ .setOldLayout(GetImpl(this)->GetLayout())
+ .setSrcAccessMask(srcAccess)
+ .setDstAccessMask(dstAccess)
+ .setSubresourceRange(subresourceRange)
+ .setImage(GetImpl(this)->GetVkImage());
+
+ return barrier;
+}
+
+void Image::SetLayout( vk::ImageLayout layout )
+{
+ GetImpl(this)->SetLayout(layout);
+}
+
+vk::ImageLayout Image::GetLayout() const
+{
+ return GetImpl(this)->GetLayout();
+}
+}
+}
+}
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_IMAGE_H
+#define DALI_CORE_GRAPHICS_VULKAN_IMAGE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class LogicalDevice;
+class DeviceMemory;
+
+class Image : public VkHandle
+{
+public:
+
+ Image(VkObject* impl = nullptr ) : VkHandle{impl}{}
+ using VkHandle::operator=;
+
+ static Image New( const LogicalDevice& device, const vk::ImageCreateInfo& createInfo );
+
+ const vk::Image& GetVkResource() const;
+ const vk::Image& operator*() const;
+
+ vk::ImageLayout GetLayout() const;
+ void SetLayout( vk::ImageLayout layout );
+ bool BindDeviceMemory( const class DeviceMemory& memory );
+ bool BindDeviceMemory( const class DeviceMemory& memory, size_t offset );
+
+ vk::ImageMemoryBarrier GetLayoutChangeBarrier( vk::ImageLayout newLayout, vk::AccessFlags srcAccess, vk::AccessFlags dstAccess, vk::ImageAspectFlags imageAspect ) const;
+
+private:
+
+};
+
+
+} // Vulkan
+} // Graphics
+} // Dali
+
+
+#endif // DALI_CORE_GRAPHICS_VULKAN_IMAGE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/command-queue.h>
+#include <dali/graphics/vulkan/frame-stack.h>
+#include <dali/graphics/vulkan/logical-device.h>
+#include <dali/graphics/vulkan/physical-device.h>
+#include <dali/graphics/vulkan/surface.h>
+#include <dali/graphics/vulkan/swapchain.h>
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+using QueueArray = std::vector< CommandQueue >;
+using FamilyQueueArray = std::vector< QueueArray >;
+
+class LogicalDeviceImpl : public GraphicsLogicalDeviceBase
+{
+public:
+ LogicalDeviceImpl(const PhysicalDevice &physicalDevice)
+ : GraphicsLogicalDeviceBase{}, mPhysicalDevice{physicalDevice}, mStack{1024}
+ {
+ }
+
+ const vk::Device &GetDevice() const
+ {
+ return mDevice;
+ }
+
+ const PhysicalDevice &GetPhysicalDevice() const
+ {
+ return mPhysicalDevice;
+ }
+
+ virtual bool Initialise() override;
+
+ virtual GraphicsSwapchain CreateSwapchain(const GraphicsSurface &surface,
+ uint32_t bufferCount,
+ DepthStencil depthStencil,
+ VSyncMode enforceVSync) override;
+
+ virtual GraphicsPhysicalDevice GetGraphicsPhysicalDevice() const override
+ {
+ return GraphicsPhysicalDevice(mPhysicalDevice);
+ }
+
+ const CommandQueue &GetCommandQueue(uint32_t index, QueueType type) const;
+
+ vk::MemoryRequirements GetResourceMemoryRequirements(const vk::Image &image) const;
+
+ vk::MemoryRequirements GetResourceMemoryRequirements(const vk::Buffer &buffer) const;
+
+ uint32_t GetMemoryIndex(uint32_t memoryTypeBits, vk::MemoryPropertyFlags properties);
+
+ template< typename T >
+ DeviceMemory AllocateMemory(T object, vk::MemoryPropertyFlags flags, bool doBind);
+
+ Image CreateImage(vk::ImageCreateInfo info);
+
+ Stack &GetStack(uint32_t stackIndex)
+ {
+ return mStack;
+ }
+
+private:
+ vk::Device mDevice{nullptr};
+ PhysicalDevice mPhysicalDevice;
+
+ ExtensionNameList mEnabledExtensionCStr;
+ std::vector< std::string > mEnabledExtensionStr;
+ FamilyQueueArray mQueueFamilyArray; // queues allocated per family
+ Stack mStack;
+ //VulkanCommandPool mTransientPool;
+};
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+bool LogicalDeviceImpl::Initialise()
+{
+ auto physDevice = mPhysicalDevice.GetPhysicalDevice();
+ auto &features = mPhysicalDevice.GetFeatures();
+ auto &stack = GetStack(0);
+ stack.Mark();
+
+ // for each family allocate all possible queues when creating device
+ auto queueInfoArray = std::vector< vk::DeviceQueueCreateInfo >{};
+
+ // make a copy of used families and sort
+ auto familyIndices = std::vector< int >{};
+
+ auto newArray = std::vector< uint32_t >{mPhysicalDevice.GetQueueFamilyIndex(QueueType::GRAPHICS),
+ mPhysicalDevice.GetQueueFamilyIndex(QueueType::COMPUTE),
+ mPhysicalDevice.GetQueueFamilyIndex(QueueType::TRANSFER),
+ mPhysicalDevice.GetQueueFamilyIndex(QueueType::SPARSE_BINDING),
+ mPhysicalDevice.GetQueueFamilyIndex(QueueType::PRESENT)};
+
+ auto queueFamilyProperties = physDevice.getQueueFamilyProperties();
+
+ std::sort(newArray.begin(), newArray.end());
+
+ mQueueFamilyArray.resize(newArray.back() + 1);
+
+ uint32_t oldIndex = -1u;
+ auto priorities = std::vector< float >{};
+ for(auto &newIndex : newArray)
+ {
+ if(newIndex != oldIndex)
+ {
+ auto &familyProperties = queueFamilyProperties[newIndex];
+
+ // set priorities ( all queues have priority 1.0 to keep it simple )
+ priorities.resize(familyProperties.queueCount);
+ std::fill(priorities.begin(), priorities.end(), 1.0f);
+
+ // just resize arrays
+ mQueueFamilyArray[newIndex].resize(familyProperties.queueCount);
+
+ vk::DeviceQueueCreateInfo queueInfo;
+ queueInfo.setQueueCount(familyProperties.queueCount);
+ queueInfo.setQueueFamilyIndex(newIndex);
+ queueInfo.setPQueuePriorities(priorities.data());
+
+ queueInfoArray.emplace_back(queueInfo);
+
+ oldIndex = newIndex;
+ }
+ }
+
+ mEnabledExtensionCStr.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+
+ auto deviceInfo = vk::DeviceCreateInfo{};
+ deviceInfo.setQueueCreateInfoCount(static_cast< uint32_t >(queueInfoArray.size()));
+ deviceInfo.setPQueueCreateInfos(queueInfoArray.data());
+ deviceInfo.setEnabledExtensionCount(static_cast< uint32_t >(mEnabledExtensionCStr.size()));
+ deviceInfo.setPpEnabledExtensionNames(mEnabledExtensionCStr.data());
+ deviceInfo.setPEnabledFeatures(&features);
+
+ VkAssertCall(physDevice.createDevice(&deviceInfo, mPhysicalDevice.GetAllocator(), &mDevice));
+
+ int familyIndex = 0;
+
+ // make a handle of the implementation
+ LogicalDevice logicalDevice(this);
+ for(auto &&family : mQueueFamilyArray)
+ {
+ for(uint32_t queueIndex = 0; queueIndex < family.size(); ++queueIndex)
+ {
+ family[queueIndex] = CommandQueue::Get(logicalDevice, static_cast< QueueType >(familyIndex), queueIndex);
+ }
+ ++familyIndex;
+ }
+
+ VkLog("[GraphicsPhysicalDevice] VkDevice created.");
+
+ return true;
+}
+#pragma GCC diagnostic pop
+
+GraphicsSwapchain LogicalDeviceImpl::CreateSwapchain(const GraphicsSurface &surface,
+ uint32_t bufferCount,
+ DepthStencil depthStencil,
+ VSyncMode enforceVSync)
+{
+ auto swapchain = Swapchain::New(LogicalDevice(this), Surface(surface.GetObject()), bufferCount, depthStencil);
+ swapchain.Initialise();
+ return swapchain;
+}
+
+const CommandQueue &LogicalDeviceImpl::GetCommandQueue(uint32_t index, QueueType type) const
+{
+ return mQueueFamilyArray[mPhysicalDevice.GetQueueFamilyIndex(type)][index];
+}
+
+vk::MemoryRequirements LogicalDeviceImpl::GetResourceMemoryRequirements(const vk::Image &image) const
+{
+ return mDevice.getImageMemoryRequirements(image);
+}
+
+vk::MemoryRequirements LogicalDeviceImpl::GetResourceMemoryRequirements(const vk::Buffer &buffer) const
+{
+ return mDevice.getBufferMemoryRequirements(buffer);
+}
+
+uint32_t LogicalDeviceImpl::GetMemoryIndex(uint32_t memoryTypeBits, vk::MemoryPropertyFlags properties)
+{
+ auto &memprops = mPhysicalDevice.GetMemoryProperties();
+ for(uint32_t i = 0; i < memprops.memoryTypeCount; ++i)
+ {
+ if((memoryTypeBits & (1u << i)) && ((memprops.memoryTypes[i].propertyFlags & properties) == properties))
+ {
+ return i;
+ }
+ }
+ return -1u;
+}
+
+template< typename T >
+DeviceMemory LogicalDeviceImpl::AllocateMemory(T object, vk::MemoryPropertyFlags flags, bool doBind)
+{
+ vk::MemoryRequirements req(GetResourceMemoryRequirements(*object));
+
+ vk::MemoryAllocateInfo info;
+ uint32_t memoryIndex = GetMemoryIndex(req.memoryTypeBits, flags);
+ assert(memoryIndex != -1u && "Wrong memory index!");
+ info.setMemoryTypeIndex(memoryIndex).setAllocationSize(req.size);
+
+ LogicalDevice deviceHandle(this);
+ DeviceMemory memory = DeviceMemory::New(deviceHandle, info);
+
+ if(doBind)
+ {
+ object.BindDeviceMemory(memory);
+ }
+
+ return memory;
+}
+
+Image LogicalDeviceImpl::CreateImage(vk::ImageCreateInfo info)
+{
+ return nullptr;
+}
+
+// End of implementation
+
+//
+
+namespace
+{
+LogicalDeviceImpl *GetImpl(const LogicalDevice *handle)
+{
+ return static_cast< LogicalDeviceImpl * >(handle->GetObject());
+}
+
+LogicalDeviceImpl *GetImpl(LogicalDevice *handle)
+{
+ return static_cast< LogicalDeviceImpl * >(handle->GetObject());
+}
+
+} //
+
+LogicalDevice LogicalDevice::New(const PhysicalDevice &physicalDevice)
+{
+ return LogicalDevice(new LogicalDeviceImpl(physicalDevice));
+}
+
+bool LogicalDevice::Initialise()
+{
+ return GetImpl(this)->Initialise();
+}
+
+const vk::Device *LogicalDevice::operator->() const
+{
+ auto &vkdevice = GetImpl(this)->GetDevice();
+ return &vkdevice;
+}
+
+DeviceMemory LogicalDevice::AllocateImageMemory(const Image &image, vk::MemoryPropertyFlags flags, bool doBind) const
+{
+ return GetImpl(this)->AllocateMemory(image, flags, doBind);
+}
+
+DeviceMemory LogicalDevice::AllocateBufferMemory(const Buffer &buffer, vk::MemoryPropertyFlags flags, bool doBind) const
+{
+ return GetImpl(this)->AllocateMemory(buffer, flags, doBind);
+}
+
+const vk::Device LogicalDevice::GetVkDevice() const
+{
+ return GetImpl(this)->GetDevice();
+}
+
+const PhysicalDevice &LogicalDevice::GetPhysicalDevice() const
+{
+ return GetImpl(this)->GetPhysicalDevice();
+}
+
+const vk::AllocationCallbacks *LogicalDevice::GetVkAllocator() const
+{
+ return GetImpl(this)->GetPhysicalDevice().GetAllocator();
+}
+
+CommandPool LogicalDevice::CreateCommandPool(QueueType type, bool createTransient, bool createResetCommandBuffer) const
+{
+ return CommandPool::New(*this, type, false, createTransient, createResetCommandBuffer);
+}
+
+const CommandQueue &LogicalDevice::GetCommandQueue(uint32_t index, QueueType type) const
+{
+ return GetImpl(this)->GetCommandQueue(index, type);
+}
+
+Image LogicalDevice::CreateImage(vk::ImageCreateInfo imageInfo)
+{
+ return GetImpl(this)->CreateImage(imageInfo);
+}
+
+Stack &LogicalDevice::GetStack(uint32_t stackIndex)
+{
+ return GetImpl(this)->GetStack(stackIndex);
+}
+}
+}
+}
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_LOGICAL_DEVICE_H
+#define DALI_CORE_GRAPHICS_VULKAN_LOGICAL_DEVICE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-logical-device.h>
+#include <dali/graphics/vulkan/buffer.h>
+#include <dali/graphics/vulkan/command-pool.h>
+#include <dali/graphics/vulkan/device-memory.h>
+#include <dali/graphics/vulkan/image.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+class PhysicalDevice;
+class CommandQueue;
+class Stack;
+
+class LogicalDevice : public GraphicsLogicalDevice
+{
+public:
+ LogicalDevice(GraphicsLogicalDeviceBase* impl = nullptr) : GraphicsLogicalDevice{impl}
+ {
+ }
+
+ using GraphicsLogicalDevice::operator=;
+
+ bool Initialise();
+
+ const vk::Device GetVkDevice() const;
+
+ const vk::AllocationCallbacks* GetVkAllocator() const;
+
+ const PhysicalDevice& GetPhysicalDevice() const;
+
+ static LogicalDevice New(const PhysicalDevice& physicalDevice);
+
+ const vk::Device* operator->() const;
+
+ Stack& GetStack(uint32_t stackIndex);
+
+ /**
+ *
+ * @param image
+ * @param flags
+ * @param doBind
+ * @return
+ */
+ DeviceMemory AllocateImageMemory(const Image& image, vk::MemoryPropertyFlags flags, bool doBind) const;
+
+ /**
+ *
+ * @param buffer
+ * @param flags
+ * @param doBind
+ * @return
+ */
+ DeviceMemory AllocateBufferMemory(const Buffer& buffer, vk::MemoryPropertyFlags flags, bool doBind) const;
+
+ /**
+ * Creates new command pool with given settings
+ * @param type
+ * @param createTransient
+ * @param createResetCommandBuffer
+ * @return
+ */
+ CommandPool CreateCommandPool(QueueType type, bool createTransient, bool createResetCommandBuffer) const;
+
+ /**
+ * Returns one of the pre-allocated command queues or nullptr
+ * @param index
+ * @param type
+ * @return
+ */
+ const CommandQueue& GetCommandQueue(uint32_t index, QueueType type) const;
+
+ // Resources
+
+ /*
+ * IMAGE
+ */
+
+ /**
+ * Creates Vulkan image object
+ * @return
+ */
+ Image CreateImage2D(uint32_t width, uint32_t height, vk::Format pixelFormat, bool hostVisible, bool bindMemory);
+
+ /**
+ * Creates Vulkan Image from given VkImageCreateInfo structure
+ * @param imageInfo
+ * @return
+ */
+ Image CreateImage(vk::ImageCreateInfo imageInfo);
+};
+
+} // Vulkan
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_LOGICAL_DEVICE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/common.h>
+#include <dali/graphics/vulkan/logical-device.h>
+#include <dali/graphics/vulkan/physical-device.h>
+#include <dali/graphics/vulkan/surface.h>
+#include <dali/graphics/vulkan/surface/xcb-surface.h>
+#include <dali/graphics/vulkan/surface/xlib-surface.h>
+#include <cstdarg>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+#define MAX_VKLOG_SIZE (1024 * 1024) // 1mb of log memory per thread
+__thread char* gLogBuffer = nullptr;
+
+// something to replace in the future, maybe
+void VkLog(const char* format, ...)
+{
+ if(!gLogBuffer)
+ {
+ gLogBuffer = new char[MAX_VKLOG_SIZE];
+ }
+ std::va_list args;
+ va_start(args, format);
+ vsnprintf(gLogBuffer, MAX_VKLOG_SIZE - 4, format, args);
+ puts(gLogBuffer);
+ va_end(args);
+}
+
+namespace
+{
+
+template< typename T >
+inline uint32_t Eval(const T& type)
+{
+ return static_cast< uint32_t >(type);
+}
+
+// debug callbacks
+#if VULKAN_USE_DEBUG_REPORT_CALLBACK
+VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char* pLayerPrefix,
+ const char* pMessage,
+ void* pUserData)
+{
+ VkLog("[VALIDATION:%s]: %s", pLayerPrefix, pMessage);
+ return VK_FALSE;
+}
+#endif
+const char* VALIDATION_LAYERS[] = {"VK_LAYER_LUNARG_screenshot", // screenshot
+ "VK_LAYER_LUNARG_parameter_validation", // parameter
+ "VK_LAYER_LUNARG_vktrace", // vktrace ( requires vktrace connection )
+ "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_LUNARG_standard_validation", // standard
+ nullptr};
+}
+
+/**
+ * Internal implementation of the Vulkan instance/physical device
+ */
+class PhysicalDeviceImpl : public Integration::GraphicsPhysicalDeviceBase
+{
+public:
+ // GraphicsPhysicalDeviceBase
+public:
+ virtual bool Initialise(const ExtensionNameList& extensions, const ValidationLayerFlags2& layers);
+
+ virtual bool IsExtensionAvailable(const std::string& instanceExtensionName);
+
+ virtual bool IsLayerAvailable(const std::string& instanceExtensionName);
+
+ virtual GraphicsLogicalDevice CreateLogicalDevice(const ExtensionNameList& enabledExtensions);
+
+ virtual bool ChoosePhysicalDevice(const PhysicalDeviceFlags& flags);
+
+ virtual void SetValidationDebugChannels(const ValidationChannelFlags& flags)
+ {
+ }
+
+ virtual GraphicsSurface CreateSurface(const NativeSurfaceCreateInfo& info);
+
+ void PrepareQueueFamilies();
+
+ // Vulkan getters
+public:
+ vk::Instance GetInstance() const
+ {
+ return mVkInstance;
+ }
+
+ vk::PhysicalDevice GetPhysicalDevice() const
+ {
+ return mVkPhysicalDevice;
+ }
+
+ const vk::PhysicalDeviceFeatures& GetFeatures() const
+ {
+ return mPhysFeatures;
+ }
+
+ const vk::PhysicalDeviceProperties& GetProperties() const
+ {
+ return mPhysProperties;
+ }
+
+ const vk::PhysicalDeviceLimits& GetLimits() const
+ {
+ return mPhysLimits;
+ }
+
+ const vk::PhysicalDeviceMemoryProperties& GetMemoryProperties() const
+ {
+ return mPhysMemoryProperties;
+ }
+
+ const std::string& GetName() const
+ {
+ return mPhysName;
+ }
+
+ const std::string& GetVendorName() const
+ {
+ return mPhysVendorName;
+ }
+
+ const vk::AllocationCallbacks* GetAllocator() const
+ {
+ return mAllocatorCallbacks;
+ }
+
+ uint32_t GetQueueFamilyIndex(QueueType type) const
+ {
+ return mQueueFamilyIndex[Eval(type)];
+ }
+
+private:
+ // Vulkan instance extension properties list
+ std::vector< vk::ExtensionProperties > mInstanceExtensionProperties;
+
+ // Vulkan device extension properties list
+ std::vector< vk::ExtensionProperties > mDeviceExtensionProperties;
+
+ // Vulkan instance layer properties list
+ std::vector< vk::LayerProperties > mInstanceLayerProperties;
+
+ // Allocators
+ vk::AllocationCallbacks* mAllocatorCallbacks{nullptr};
+
+ // Instance
+ vk::Instance mVkInstance{nullptr};
+
+ // Physical device
+ vk::PhysicalDevice mVkPhysicalDevice{nullptr};
+ vk::PhysicalDeviceFeatures mPhysFeatures{};
+ vk::PhysicalDeviceProperties mPhysProperties{};
+ vk::PhysicalDeviceMemoryProperties mPhysMemoryProperties{};
+ vk::PhysicalDeviceType mPhysType;
+ vk::PhysicalDeviceLimits mPhysLimits;
+ uint32_t mPhysApiVersion{0};
+ uint32_t mPhysDriverVersion{0};
+ std::string mPhysName;
+ std::string mPhysVendorName;
+ bool mPhysIsDiscrete{false};
+
+ // Queue families
+ std::vector< vk::QueueFamilyProperties > mQueueFamilyProperties;
+ std::array< uint32_t, static_cast< uint32_t >(QueueType::END) > mQueueFamilyIndex;
+
+ // todo add surface type register
+};
+
+bool PhysicalDeviceImpl::IsExtensionAvailable(const std::string& instanceExtensionName)
+{
+ if(mInstanceExtensionProperties.empty())
+ {
+ auto result = vk::enumerateInstanceExtensionProperties();
+ if(result.result != vk::Result::eSuccess)
+ {
+ // todo no vulkan support????
+ return false;
+ }
+ mInstanceExtensionProperties = std::move(result.value);
+ }
+
+ for(auto&& ext : mInstanceExtensionProperties)
+ {
+ if(instanceExtensionName == ext.extensionName)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PhysicalDeviceImpl::IsLayerAvailable(const std::string& instanceLayerName)
+{
+ if(mInstanceLayerProperties.empty())
+ {
+ auto result = vk::enumerateInstanceLayerProperties();
+ if(result.result != vk::Result::eSuccess)
+ {
+ // todo no vulkan support????
+ return false;
+ }
+ mInstanceLayerProperties = std::move(result.value);
+ }
+
+ for(auto&& ext : mInstanceLayerProperties)
+ {
+ if(instanceLayerName == ext.layerName)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PhysicalDeviceImpl::Initialise(const ExtensionNameList& extensions, const ValidationLayerFlags2& layers)
+{
+ // make a copy and add debug report extension in case there are any
+ // validation layers listed
+ auto extCopy = ExtensionNameList{extensions};
+ if(layers != 0u)
+ {
+ extCopy.emplace_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
+ }
+
+ // add validation layers
+ LayerNameList layerTable;
+ auto retval = LayerNameList{};
+
+ for(uint32_t bit = 0; VALIDATION_LAYERS[bit]; ++bit)
+ {
+ if(layers & (1u << bit))
+ {
+ layerTable.emplace_back(VALIDATION_LAYERS[bit]);
+ }
+ }
+
+ vk::InstanceCreateInfo info;
+ info.setEnabledExtensionCount(static_cast<uint32_t>(extCopy.size()))
+ .setPpEnabledExtensionNames(extCopy.data())
+ .setPApplicationInfo(nullptr)
+ .setPpEnabledLayerNames(layerTable.empty() ? nullptr : layerTable.data())
+ .setEnabledLayerCount(static_cast<uint32_t>(layerTable.size()));
+
+ return (vk::Result::eSuccess == VkTestCall(vk::createInstance(&info, mAllocatorCallbacks, &mVkInstance)));
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+bool PhysicalDeviceImpl::ChoosePhysicalDevice(const PhysicalDeviceFlags& flags)
+{
+ auto preferredDiscrete = flags & PhysicalDeviceBit::DISCRETE ? true : false;
+
+ // set preferred device type
+ const vk::PhysicalDeviceType preferredType =
+ preferredDiscrete ? vk::PhysicalDeviceType::eDiscreteGpu : vk::PhysicalDeviceType::eIntegratedGpu;
+
+ // set fallback device type
+ const vk::PhysicalDeviceType fallbackType =
+ preferredDiscrete ? vk::PhysicalDeviceType::eIntegratedGpu : vk::PhysicalDeviceType::eDiscreteGpu;
+
+ auto result = mVkInstance.enumeratePhysicalDevices();
+ VkAssertCallMsg(result.result, "No Vulkan devices found!");
+
+ auto GPUs = result.value;
+ auto currentGPU = GPUs.front();
+ auto currentGPUProps = currentGPU.getProperties();
+
+ // select discreet over integrated
+ for(auto&& gpu : GPUs)
+ {
+ auto gpuProperties = gpu.getProperties();
+ if((currentGPUProps.deviceType != preferredType && gpuProperties.deviceType == preferredType) ||
+ (currentGPUProps.deviceType != preferredType && gpuProperties.deviceType == fallbackType))
+ {
+ currentGPU = gpu;
+ currentGPUProps = gpuProperties;
+ }
+ }
+
+ // make sure selected GPU is THE REAL GPU not a blanket or refrigerator
+ if(currentGPUProps.deviceType != preferredType && currentGPUProps.deviceType != fallbackType)
+ {
+ // error
+ return false;
+ }
+
+ // store GPU data
+ // fixme
+ auto& gpu = currentGPU;
+ auto& gpuProperties = currentGPUProps;
+ auto gpuMemoryProperties = currentGPU.getMemoryProperties();
+ auto gpuFeatures = currentGPU.getFeatures();
+
+ auto deviceExtensionProperties = gpu.enumerateDeviceExtensionProperties();
+ mDeviceExtensionProperties = deviceExtensionProperties.value;
+
+ auto queueFamilyProperties = gpu.getQueueFamilyProperties();
+
+ // collect all physical device related information
+ mPhysIsDiscrete = preferredDiscrete;
+ mVkPhysicalDevice = gpu;
+ mPhysProperties = gpuProperties;
+ mPhysFeatures = gpuFeatures;
+ mPhysMemoryProperties = gpuMemoryProperties;
+ mPhysLimits = mPhysProperties.limits;
+ mPhysType = mPhysProperties.deviceType;
+
+ // fill common stuff
+ mPhysName = mPhysProperties.deviceName;
+
+ switch(mPhysProperties.vendorID)
+ {
+ case 0x10DE: //nvidia
+ mPhysVendorName = "NVIDIA";
+ break;
+ default:
+ mPhysVendorName = "Unknown";
+ }
+
+ mPhysApiVersion = mPhysProperties.apiVersion;
+ mPhysDriverVersion = mPhysProperties.driverVersion;
+
+ VkLog("[Vulkan] Found physical device: %s", mPhysName.c_str());
+ VkLog("[Vulkan] vendor: %s", mPhysVendorName.c_str());
+
+ // prepare queue families
+ PrepareQueueFamilies();
+
+ return true;
+}
+#pragma GCC diagnostic pop
+
+GraphicsLogicalDevice PhysicalDeviceImpl::CreateLogicalDevice(const ExtensionNameList& enabledExtensions)
+{
+ LogicalDevice logicDevice(LogicalDevice::New(this));
+ if(!logicDevice.Initialise())
+ {
+ logicDevice = nullptr;
+ }
+ return logicDevice;
+}
+
+void PhysicalDeviceImpl::PrepareQueueFamilies()
+{
+ uint32_t& familyGraphics{mQueueFamilyIndex[Eval(QueueType::GRAPHICS)]};
+ uint32_t& familyTransfer{mQueueFamilyIndex[Eval(QueueType::TRANSFER)]};
+ uint32_t& familyCompute{mQueueFamilyIndex[Eval(QueueType::COMPUTE)]};
+ uint32_t& familySparseBinding{mQueueFamilyIndex[Eval(QueueType::SPARSE_BINDING)]};
+ uint32_t& familyPresent{mQueueFamilyIndex[Eval(QueueType::PRESENT)]};
+ familyGraphics = familyTransfer = familyCompute = familySparseBinding = familyPresent = -1u;
+
+ mQueueFamilyProperties = mVkPhysicalDevice.getQueueFamilyProperties();
+
+ uint32_t queueIndex = 0;
+ for(auto&& queueFamily : mQueueFamilyProperties)
+ {
+ if(familyGraphics == -1u && (queueFamily.queueFlags | vk::QueueFlagBits::eGraphics))
+ {
+ familyGraphics = queueIndex;
+ }
+ if(familyTransfer == -1u && (queueFamily.queueFlags | vk::QueueFlagBits::eTransfer))
+ {
+ familyTransfer = queueIndex;
+ }
+ if(familyCompute == -1u && (queueFamily.queueFlags | vk::QueueFlagBits::eCompute))
+ {
+ familyCompute = queueIndex;
+ }
+ if(familySparseBinding == -1u && (queueFamily.queueFlags | vk::QueueFlagBits::eSparseBinding))
+ {
+ familySparseBinding = queueIndex;
+ }
+
+ ++queueIndex;
+ }
+}
+
+GraphicsSurface PhysicalDeviceImpl::CreateSurface(const NativeSurfaceCreateInfo& info)
+{
+ uint32_t& familyPresent{mQueueFamilyIndex[Eval(QueueType::PRESENT)]};
+
+ assert(familyPresent == -1u && "Looks like the surface has been created!");
+
+ // should be part of adaptor????
+ GraphicsSurface retval{nullptr};
+ if(info.surfaceType == NativeSurfaceType::XCB)
+ {
+ const XcbSurfaceCreateInfo* xcbInfo = reinterpret_cast< const XcbSurfaceCreateInfo* >(&info);
+ GraphicsPhysicalDevice physDevice(this);
+ retval = Surface::New< XcbSurface >(physDevice, xcbInfo->connection, xcbInfo->window);
+ }
+ else if(info.surfaceType == NativeSurfaceType::X11)
+ {
+ const XlibSurfaceCreateInfo* xlibInfo = reinterpret_cast< const XlibSurfaceCreateInfo* >(&info);
+ GraphicsPhysicalDevice physDevice(this);
+ retval = Surface::New< XlibSurface >(physDevice, xlibInfo->display, xlibInfo->window);
+ }
+ // check surface compatibility against queue families
+ uint32_t queueIndex = 0;
+ for(size_t i = 0; i < mQueueFamilyProperties.size(); ++i)
+ {
+
+ // set present family upon surface creation
+ if(familyPresent == -1u)
+ {
+ vk::Bool32 supported{false};
+
+ mVkPhysicalDevice.getSurfaceSupportKHR(queueIndex, Surface(retval.GetObject()).GetSurface(), &supported);
+ if(supported)
+ {
+ familyPresent = queueIndex;
+ break;
+ }
+ }
+ ++queueIndex;
+ }
+
+ assert(familyPresent != -1u && "Surface not supported");
+
+ return retval;
+}
+
+/**************************************************************************
+ * Handle implementation
+ */
+
+PhysicalDeviceImpl* GetImpl(const PhysicalDevice* handle)
+{
+ return static_cast< PhysicalDeviceImpl* >(handle->GetObject());
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlarger-than="
+GraphicsPhysicalDevice PhysicalDevice::New()
+{
+ return GraphicsPhysicalDevice(new PhysicalDeviceImpl());
+}
+#pragma GCC diagnostic pop
+
+vk::Instance PhysicalDevice::GetInstance() const
+{
+ return GetImpl(this)->GetInstance();
+}
+
+vk::PhysicalDevice PhysicalDevice::GetPhysicalDevice() const
+{
+ return GetImpl(this)->GetPhysicalDevice();
+}
+
+const vk::PhysicalDeviceFeatures& PhysicalDevice::GetFeatures() const
+{
+ return GetImpl(this)->GetFeatures();
+}
+
+const vk::PhysicalDeviceProperties& PhysicalDevice::GetProperties() const
+{
+ return GetImpl(this)->GetProperties();
+}
+
+const vk::PhysicalDeviceLimits& PhysicalDevice::GetLimits() const
+{
+ return GetImpl(this)->GetLimits();
+}
+
+const vk::PhysicalDeviceMemoryProperties& PhysicalDevice::GetMemoryProperties() const
+{
+ return GetImpl(this)->GetMemoryProperties();
+}
+
+const std::string& PhysicalDevice::GetName() const
+{
+ return GetImpl(this)->GetName();
+}
+
+const std::string& PhysicalDevice::GetVendorName() const
+{
+ return GetImpl(this)->GetVendorName();
+}
+
+const vk::AllocationCallbacks* PhysicalDevice::GetAllocator() const
+{
+ return GetImpl(this)->GetAllocator();
+}
+
+uint32_t PhysicalDevice::GetQueueFamilyIndex(QueueType type) const
+{
+ return GetImpl(this)->GetQueueFamilyIndex(type);
+}
+
+} // Vulkan
+} // Graphics
+} // Dali
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_PHYSICAL_DEVICE_H
+#define DALI_CORE_GRAPHICS_VULKAN_PHYSICAL_DEVICE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-physical-device.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+class PhysicalDevice : public GraphicsPhysicalDevice
+{
+public:
+ PhysicalDevice(Integration::GraphicsPhysicalDeviceBase* impl = nullptr)
+ : GraphicsPhysicalDevice{impl}
+ {
+ }
+
+ using GraphicsPhysicalDevice::operator=;
+
+ // must not be virtual! ( for now )
+ static GraphicsPhysicalDevice New();
+
+ uint32_t GetQueueFamilyIndex(QueueType type) const;
+
+public:
+ // getters of bound Vulkan objects
+ vk::Instance GetInstance() const;
+ vk::PhysicalDevice GetPhysicalDevice() const;
+ const vk::AllocationCallbacks* GetAllocator() const;
+ const vk::PhysicalDeviceFeatures& GetFeatures() const;
+ const vk::PhysicalDeviceProperties& GetProperties() const;
+ const vk::PhysicalDeviceLimits& GetLimits() const;
+ const vk::PhysicalDeviceMemoryProperties& GetMemoryProperties() const;
+ const std::string& GetName() const;
+ const std::string& GetVendorName() const;
+};
+}
+}
+}
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_PHYSICAL_DEVICE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/surface.h>
+#include <dali/graphics/vulkan/surface/vulkan-surface-base.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+
+uint32_t Surface::GetWidth() const
+{
+ return GetObject()->GetWidth();
+}
+
+uint32_t Surface::GetHeight() const
+{
+ return GetObject()->GetHeight();
+}
+
+const vk::SurfaceKHR Surface::GetSurface() const
+{
+ return static_cast<VulkanSurfaceBase*>(GetObject())->GetVkSurface();
+}
+
+const vk::SurfaceFormatKHR& Surface::GetFormat() const
+{
+ return static_cast<VulkanSurfaceBase*>(GetObject())->GetVkSurfaceFormat();
+}
+
+const vk::SurfaceCapabilitiesKHR& Surface::GetCapabilities() const
+{
+ return static_cast<VulkanSurfaceBase*>(GetObject())->GetCapabilities();
+}
+
+const std::vector< vk::SurfaceFormatKHR >& Surface::GetAllFormats() const
+{
+ return static_cast<VulkanSurfaceBase*>(GetObject())->GetAllFormats();
+}
+
+} // Vulkan
+} // Graphics
+} // Dali
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_SURFACE_H
+#define DALI_CORE_GRAPHICS_VULKAN_SURFACE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-surface.h>
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+/**
+ * This is a common handle for Vulkan surface implementation
+ */
+class Surface : public GraphicsSurface
+{
+public:
+ Surface(Integration::GraphicsSurfaceBase* impl = nullptr) : GraphicsSurface{impl}
+ {
+ }
+ using GraphicsSurface::operator=;
+
+ /**
+ * Returns surface width
+ * @return
+ */
+ uint32_t GetWidth() const;
+
+ /**
+ * Returns surface height
+ * @return
+ */
+ uint32_t GetHeight() const;
+
+ // Vulkan specific API
+public:
+ /**
+ * Returns associated Vulkan surface object
+ * @return
+ */
+ const vk::SurfaceKHR GetSurface() const;
+
+ /**
+ * Returns current surface format
+ * @return
+ */
+ const vk::SurfaceFormatKHR& GetFormat() const;
+
+ /**
+ *
+ * @return
+ */
+ const vk::SurfaceCapabilitiesKHR& GetCapabilities() const;
+
+ /**
+ *
+ * @return
+ */
+ const std::vector< vk::SurfaceFormatKHR >& GetAllFormats() const;
+};
+
+} // Vulkan
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_SURFACE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#ifndef DALI_CORE_VULKAN_SURFACE_BASE_H
+#define DALI_CORE_VULKAN_SURFACE_BASE_H
+
+#include <dali/graphics/integration/graphics-surface-base.h>
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+
+namespace Vulkan
+{
+
+/**
+ * Internal interface inherited by the Surface implementation
+ */
+class VulkanSurfaceBase : public Integration::GraphicsSurfaceBase
+{
+public:
+ VulkanSurfaceBase(const GraphicsPhysicalDevice& physicalDevice)
+ : Integration::GraphicsSurfaceBase(physicalDevice){};
+ virtual ~VulkanSurfaceBase() = default;
+
+ virtual const vk::SurfaceKHR GetVkSurface() const = 0;
+ virtual const vk::SurfaceFormatKHR& GetVkSurfaceFormat() const = 0;
+ virtual const vk::SurfaceCapabilitiesKHR& GetCapabilities() const = 0;
+ virtual const std::vector< vk::SurfaceFormatKHR >& GetAllFormats() const = 0;
+};
+}
+}
+}
+
+#endif //DALI_CORE_VULKAN_SURFACE_BASE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/physical-device.h>
+#include <dali/graphics/vulkan/surface/xcb-surface.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+XcbSurface::XcbSurface(const GraphicsPhysicalDevice &device, xcb_connection_t *connection, xcb_window_t window)
+: VulkanSurfaceBase(device), mPhysicalDevice(device), mConnection(connection), mWindow(window)
+{
+}
+
+// GraphicsSurfaceBase
+
+bool XcbSurface::Initialise()
+{
+ xcb_generic_error_t *err;
+
+ PhysicalDevice device(mPhysicalDevice.GetObject());
+
+ auto cookie = xcb_get_geometry(mConnection, mWindow);
+ auto reply = xcb_get_geometry_reply(mConnection, cookie, &err);
+
+ mSurfaceWidth = reply->width;
+ mSurfaceHeight = reply->height;
+
+ auto vkInstance = device.GetInstance();
+ auto vkAllocator = device.GetAllocator();
+ vk::XcbSurfaceCreateInfoKHR info;
+ info.setConnection(mConnection).setWindow(mWindow);
+
+ VkAssertCall(vkInstance.createXcbSurfaceKHR(&info, vkAllocator, &mSurface));
+
+ mFormats = device.GetPhysicalDevice().getSurfaceFormatsKHR(mSurface).value;
+ mCapabilities = device.GetPhysicalDevice().getSurfaceCapabilitiesKHR(mSurface).value;
+ mDefaultFormat = mFormats[0];
+ for(auto&& format : mFormats)
+ {
+ if(format.format == vk::Format::eR8G8B8A8Unorm)
+ {
+ mDefaultFormat = format;
+ }
+ }
+
+ return true;
+}
+
+bool XcbSurface::Replace()
+{
+ assert( true && "XcbSurface::Replace() not implemented!");
+ return false;
+}
+
+bool XcbSurface::Destroy()
+{
+ assert( true && "XcbSurface::Destroy() not implemented!");
+ return false;
+}
+
+uint32_t XcbSurface::GetWidth()
+{
+ return mSurfaceWidth;
+}
+
+uint32_t XcbSurface::GetHeight()
+{
+ return mSurfaceHeight;
+}
+
+// VulkanSurfaceBase
+
+const vk::SurfaceKHR XcbSurface::GetVkSurface() const
+{
+ return mSurface;
+}
+
+const vk::SurfaceFormatKHR& XcbSurface::GetVkSurfaceFormat() const
+{
+ return mDefaultFormat;
+}
+
+const vk::SurfaceCapabilitiesKHR& XcbSurface::GetCapabilities() const
+{
+ return mCapabilities;
+}
+
+const std::vector< vk::SurfaceFormatKHR >& XcbSurface::GetAllFormats() const
+{
+ return mFormats;
+}
+
+
+}
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_XCB_SURFACE_H
+#define DALI_CORE_GRAPHICS_VULKAN_XCB_SURFACE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/surface/vulkan-surface-base.h>
+#include <xcb/xcb.h>
+#include <cinttypes>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+
+struct XcbSurfaceCreateInfo : NativeSurfaceCreateInfo
+{
+ XcbSurfaceCreateInfo() : NativeSurfaceCreateInfo(NativeSurfaceType::XCB)
+ {
+ }
+ xcb_connection_t* connection;
+ xcb_window_t window;
+};
+
+namespace Vulkan
+{
+
+/**
+ * Implementation of Xcb surface
+ */
+class XcbSurface : public VulkanSurfaceBase
+{
+public:
+ XcbSurface(const GraphicsPhysicalDevice& adaptor, xcb_connection_t* connection, xcb_window_t window);
+
+ virtual ~XcbSurface() = default;
+
+ // GraphicsSurfaceBase
+
+ virtual bool Initialise();
+
+ virtual bool Replace();
+
+ virtual bool Destroy();
+
+ virtual uint32_t GetWidth();
+
+ virtual uint32_t GetHeight();
+
+ // VulkanSurfaceBase
+
+ virtual const vk::SurfaceKHR GetVkSurface() const;
+
+ virtual const vk::SurfaceFormatKHR& GetVkSurfaceFormat() const;
+
+ virtual const vk::SurfaceCapabilitiesKHR& GetCapabilities() const;
+
+ virtual const std::vector< vk::SurfaceFormatKHR >& GetAllFormats() const;
+
+private:
+ GraphicsPhysicalDevice mPhysicalDevice{nullptr};
+
+ vk::SurfaceKHR mSurface{nullptr};
+ vk::SurfaceCapabilitiesKHR mCapabilities{};
+ vk::SurfaceFormatKHR mDefaultFormat{};
+ std::vector< vk::SurfaceFormatKHR > mFormats{};
+
+ uint32_t mSurfaceWidth{0u};
+ uint32_t mSurfaceHeight{0u};
+
+ xcb_connection_t* mConnection{nullptr};
+ xcb_window_t mWindow{};
+};
+}
+}
+}
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_XCB_SURFACE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/physical-device.h>
+#include <dali/graphics/vulkan/surface/xlib-surface.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+XlibSurface::XlibSurface(const GraphicsPhysicalDevice &device, Display* display, Window window)
+: VulkanSurfaceBase(device), mPhysicalDevice(device), mDisplay(display), mWindow(window)
+{
+}
+
+// GraphicsSurfaceBase
+
+bool XlibSurface::Initialise()
+{
+ PhysicalDevice device(mPhysicalDevice.GetObject());
+
+ Window root;
+ int x, y;
+ unsigned int width, height, borderWidth, depth;
+
+ XGetGeometry( mDisplay, mWindow, &root, &x, &y, &width, &height, &borderWidth, &depth );
+
+ mSurfaceWidth = width;
+ mSurfaceHeight = height;
+
+ auto vkInstance = device.GetInstance();
+ auto vkAllocator = device.GetAllocator();
+ vk::XlibSurfaceCreateInfoKHR info;
+ info.setWindow( mWindow );
+ info.setDpy( mDisplay );
+
+ VkAssertCall(vkInstance.createXlibSurfaceKHR(&info, vkAllocator, &mSurface));
+
+ mFormats = device.GetPhysicalDevice().getSurfaceFormatsKHR(mSurface).value;
+ mCapabilities = device.GetPhysicalDevice().getSurfaceCapabilitiesKHR(mSurface).value;
+ mDefaultFormat = mFormats[0];
+ for(auto&& format : mFormats)
+ {
+ if(format.format == vk::Format::eR8G8B8A8Unorm)
+ {
+ mDefaultFormat = format;
+ }
+ }
+
+ return true;
+}
+
+bool XlibSurface::Replace()
+{
+ assert( "XcbSurface::Replace() not implemented!");
+ return false;
+}
+
+bool XlibSurface::Destroy()
+{
+ assert( "XcbSurface::Destroy() not implemented!");
+ return false;
+}
+
+uint32_t XlibSurface::GetWidth()
+{
+ return mSurfaceWidth;
+}
+
+uint32_t XlibSurface::GetHeight()
+{
+ return mSurfaceHeight;
+}
+
+// VulkanSurfaceBase
+
+const vk::SurfaceKHR XlibSurface::GetVkSurface() const
+{
+ return mSurface;
+}
+
+const vk::SurfaceFormatKHR& XlibSurface::GetVkSurfaceFormat() const
+{
+ return mDefaultFormat;
+}
+
+const vk::SurfaceCapabilitiesKHR& XlibSurface::GetCapabilities() const
+{
+ return mCapabilities;
+}
+
+const std::vector< vk::SurfaceFormatKHR >& XlibSurface::GetAllFormats() const
+{
+ return mFormats;
+}
+
+
+}
+}
+}
\ No newline at end of file
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_XLIB_SURFACE_H
+#define DALI_CORE_GRAPHICS_VULKAN_XLIB_SURFACE_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <X11/Xlib.h>
+#include <dali/graphics/vulkan/surface/vulkan-surface-base.h>
+#include <cinttypes>
+
+namespace Dali
+{
+namespace Graphics
+{
+class GraphicsPhysicalDevice;
+
+struct XlibSurfaceCreateInfo : NativeSurfaceCreateInfo
+{
+ XlibSurfaceCreateInfo() : NativeSurfaceCreateInfo(NativeSurfaceType::X11)
+ {
+ }
+ Display* display;
+ Window window;
+};
+
+namespace Vulkan
+{
+
+/**
+ * Implementation of Xlib surface
+ */
+class XlibSurface : public VulkanSurfaceBase
+{
+public:
+ XlibSurface(const GraphicsPhysicalDevice& device, Display* display, Window window);
+
+ virtual ~XlibSurface() = default;
+
+ // GraphicsSurfaceBase
+
+ virtual bool Initialise();
+
+ virtual bool Replace();
+
+ virtual bool Destroy();
+
+ virtual uint32_t GetWidth();
+
+ virtual uint32_t GetHeight();
+
+ // VulkanSurfaceBase
+
+ virtual const vk::SurfaceKHR GetVkSurface() const;
+
+ virtual const vk::SurfaceFormatKHR& GetVkSurfaceFormat() const;
+
+ virtual const vk::SurfaceCapabilitiesKHR& GetCapabilities() const;
+
+ virtual const std::vector< vk::SurfaceFormatKHR >& GetAllFormats() const;
+
+private:
+ GraphicsPhysicalDevice mPhysicalDevice{nullptr};
+
+ vk::SurfaceKHR mSurface{nullptr};
+ vk::SurfaceCapabilitiesKHR mCapabilities{};
+ vk::SurfaceFormatKHR mDefaultFormat{};
+ std::vector< vk::SurfaceFormatKHR > mFormats{};
+
+ uint32_t mSurfaceWidth{0u};
+ uint32_t mSurfaceHeight{0u};
+
+ Display* mDisplay{nullptr};
+ Window mWindow{};
+};
+}
+}
+}
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_XLIB_SURFACE_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/vulkan/command-buffer.h>
+#include <dali/graphics/vulkan/command-pool.h>
+#include <dali/graphics/vulkan/command-queue.h>
+#include <dali/graphics/vulkan/device-memory.h>
+#include <dali/graphics/vulkan/frame-stack.h>
+#include <dali/graphics/vulkan/image.h>
+#include <dali/graphics/vulkan/logical-device.h>
+#include <dali/graphics/vulkan/surface.h>
+#include <dali/graphics/vulkan/swapchain.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+struct SwapchainFramebuffer
+{
+ vk::Framebuffer framebuffer{nullptr};
+
+ vk::Image image{nullptr};
+ vk::ImageView imageView{nullptr};
+ vk::ImageLayout layout{vk::ImageLayout::eUndefined};
+
+ CommandBuffer commandBuffer;
+ bool submitted{false};
+ vk::Fence fence{nullptr};
+};
+
+using SwapchainBufferArray = std::vector< SwapchainFramebuffer >;
+
+// swapchain implementation
+class SwapchainImpl : public Integration::GraphicsSwapchainBase
+{
+public:
+ SwapchainImpl(const LogicalDevice& device, const Vulkan::Surface& surface, uint32_t bufferCount,
+ DepthStencil depthStencil);
+ virtual ~SwapchainImpl() = default;
+
+ /**
+ * Presents frame
+ * @param queue
+ */
+ void Present(const CommandQueue& queue);
+
+ /**
+ *
+ */
+ void Present();
+
+ /**
+ * Begins new frame
+ */
+ void BeginFrame();
+
+ /**
+ * Replace swapchain
+ */
+ void Replace();
+
+ /**
+ * Creates optional depth/stencil buffer
+ */
+ void CreateDepthStencil();
+
+ /**
+ * Obtains swapchain images
+ */
+ void GetSwapchainImages();
+
+ /**
+ * Creates main render pass used by swapchain
+ */
+ void CreateMainRenderPass();
+
+ /**
+ * Creates main commandbuffers related to the swapchain
+ */
+ void CreateCommandBuffers();
+
+ /**
+ * Creates necessary semaphores
+ */
+ void CreateSemaphores();
+
+ /**
+ *
+ * @param index
+ * @return
+ */
+ const CommandBuffer& GetCommandBuffer(uint32_t index) const
+ {
+ return mBuffers[index].commandBuffer;
+ }
+
+ /**
+ *
+ * @return
+ */
+ const CommandBuffer& GetCurrentCommandBuffer() const
+ {
+ return mBuffers[mAcquiredBufferIndex].commandBuffer;
+ }
+
+ const vk::Image& GetCurrentImage() const
+ {
+ return mBuffers[mAcquiredBufferIndex].image;
+ }
+
+ // swapchain integration
+public:
+ virtual bool Initialise();
+
+ virtual bool AcquireFrame();
+
+ virtual bool PresentFrame();
+
+private:
+ void GenerateViewFramebuffer(uint32_t bufferIndex, const vk::Image& image);
+
+ void BeginRenderPass(CommandBuffer& cmdbuf);
+ void RecordDepthStencilBarrier(vk::ImageMemoryBarrier& barrier);
+ void RecordColorBarrier(vk::ImageMemoryBarrier& barrier, SwapchainFramebuffer& swapbuffer);
+ void AcquireNextImage();
+
+ vk::SwapchainKHR mVkSwapchain{nullptr};
+ vk::SwapchainKHR mVkOldSwapchain{nullptr};
+
+ // Depth/stencil
+ Image mVkDepthStencilImage{nullptr};
+ vk::ImageView mVkDepthStencilImageView{nullptr};
+ DeviceMemory mVkDepthStencilImageMemory{nullptr};
+ vk::Format mDepthStencilFormat{};
+ bool mDepthStencilLayoutChangeNeeded{false}; // this flag indicates whether with new frame it's also necessary to change image layout (done once only)
+
+ // renderpass
+ vk::RenderPass mRenderPass{nullptr};
+
+ LogicalDevice mDevice;
+
+ Surface mSurface;
+
+ SwapchainBufferArray mBuffers{};
+
+ std::vector< vk::Semaphore > mAcquireSemaphore; // array of semaphores, can't be placed inside the buffer as
+ // we don't know the first index
+ std::vector< vk::Semaphore > mPresentSemaphore;
+
+ CommandPool mCommandPool{nullptr}; // command pool
+
+ uint32_t mCurrentBufferIndex{0};
+ uint32_t mAcquiredBufferIndex{-1u};
+ uint32_t mMaxBufferCount{-1u};
+ DepthStencil mDepthStencilMode;
+};
+
+SwapchainImpl::SwapchainImpl(const LogicalDevice& device, const Vulkan::Surface& surface,
+ uint32_t bufferCount, DepthStencil depthStencil)
+: GraphicsSwapchainBase(), mDevice(device), mSurface{surface}, mMaxBufferCount(bufferCount), mDepthStencilMode(depthStencil)
+{
+}
+
+bool SwapchainImpl::Initialise()
+{
+ // create new command pool for new swapchain
+ if(!mCommandPool)
+ {
+ mCommandPool = mDevice.CreateCommandPool(QueueType::GRAPHICS, false, false);
+ }
+ // just replace swapchain
+ Replace();
+ return true;
+}
+
+bool SwapchainImpl::AcquireFrame()
+{
+ BeginFrame();
+ return true;
+}
+
+bool SwapchainImpl::PresentFrame()
+{
+ Present();
+ return true;
+}
+
+/**
+ * Replacing surface makes sure all device operations completed as new surface will bring a
+ * new image resources etc.
+ */
+void SwapchainImpl::Replace()
+{
+
+ // wait for device to finish
+ if(mVkSwapchain)
+ {
+ // Todo: make sure no other part of implementation is executing on other threads
+ // This situation is very rare so vkDeviceWaitIdle() won't hurt performance
+ mDevice.GetVkDevice().waitIdle();
+
+ mVkOldSwapchain = mVkSwapchain;
+ mVkSwapchain = nullptr;
+
+ // todo: if size of surface changed the depth may need to be recreated
+ // vkDestroyImageView()
+ // vkDestroyImage()
+ }
+
+ vk::SwapchainCreateInfoKHR info;
+ info.setSurface(mSurface.GetSurface())
+ .setQueueFamilyIndexCount(0)
+ .setPQueueFamilyIndices(nullptr)
+ .setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity)
+ .setPresentMode(vk::PresentModeKHR::eFifo)
+ .setOldSwapchain(mVkOldSwapchain)
+ .setMinImageCount(mMaxBufferCount)
+ .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst)
+ .setImageSharingMode(vk::SharingMode::eExclusive)
+ .setImageExtent({mSurface.GetWidth(), mSurface.GetHeight()})
+ .setImageFormat(mSurface.GetFormat().format)
+ .setImageColorSpace(mSurface.GetFormat().colorSpace)
+ .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
+ .setImageArrayLayers(1)
+ .setClipped(true);
+
+ VkAssertCall(mDevice.GetVkDevice().createSwapchainKHR(&info, mDevice.GetVkAllocator(), &mVkSwapchain));
+
+ CreateMainRenderPass();
+
+ // create depth stencil buffer
+ CreateDepthStencil();
+
+ // extract images ( no need to delete existing ones except of views )
+ GetSwapchainImages();
+
+ // Create semaphores ( 2 per buffer );
+ CreateSemaphores();
+
+ // create command buffers ( won't do anything if buffers are already allocated )
+ // fixme: it might not be a good idea to reuse previous buffers
+ CreateCommandBuffers();
+
+ mCurrentBufferIndex = 0;
+}
+
+void SwapchainImpl::CreateDepthStencil()
+{
+ if(mDepthStencilMode == DepthStencil::NONE)
+ {
+ return;
+ }
+
+ // free any existing depth buffer
+ if(mVkDepthStencilImageView)
+ {
+ mDevice.GetVkDevice().destroyImageView(mVkDepthStencilImageView, mDevice.GetVkAllocator());
+ }
+ if(mVkDepthStencilImage)
+ {
+ //mDevice.GetVkDevice().destroyImage(mVkDepthStencilImage, mDevice.GetVkAllocator());
+ mVkDepthStencilImage = nullptr;
+ }
+
+ // todo: include the proper depth stencil settings
+ vk::Format format = vk::Format::eD16Unorm;
+ mDepthStencilFormat = format;
+
+ Stack stack(1024);
+
+ auto& imageInfo = *stack.AllocNew< vk::ImageCreateInfo >();
+ auto& imageViewInfo = *stack.AllocNew< vk::ImageViewCreateInfo >();
+
+ imageInfo.setPQueueFamilyIndices(nullptr)
+ .setQueueFamilyIndexCount(0)
+ .setSamples(vk::SampleCountFlagBits::e1)
+ .setInitialLayout(vk::ImageLayout::eUndefined)
+ .setArrayLayers(1)
+ .setExtent({mSurface.GetWidth(), mSurface.GetHeight(), 1})
+ .setImageType(vk::ImageType::e2D)
+ .setMipLevels(1)
+ .setSharingMode(vk::SharingMode::eExclusive)
+ .setTiling(vk::ImageTiling::eOptimal)
+ .setFormat(format)
+ .setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment);
+
+ // create image
+ mVkDepthStencilImage = Image::New(mDevice, imageInfo);
+
+ imageViewInfo.setFormat(format)
+ .setSubresourceRange(vk::ImageSubresourceRange()
+ .setLayerCount(1)
+ .setBaseArrayLayer(0)
+ .setBaseMipLevel(0)
+ .setLevelCount(1)
+ .setLayerCount(1)
+ .setAspectMask(vk::ImageAspectFlagBits::eDepth))
+ .setImage(*mVkDepthStencilImage)
+ .setViewType(vk::ImageViewType::e2D)
+ .setComponents(vk::ComponentMapping()
+ .setR(vk::ComponentSwizzle::eR)
+ .setG(vk::ComponentSwizzle::eG)
+ .setB(vk::ComponentSwizzle::eB)
+ .setA(vk::ComponentSwizzle::eA));
+
+ // create view
+ VkAssertCall(mDevice.GetVkDevice().createImageView(&imageViewInfo, mDevice.GetVkAllocator(),
+ &mVkDepthStencilImageView));
+
+ // allocate memory
+ mVkDepthStencilImageMemory =
+ mDevice.AllocateImageMemory(mVkDepthStencilImage, vk::MemoryPropertyFlagBits::eDeviceLocal, false);
+ mVkDepthStencilImage.BindDeviceMemory(mVkDepthStencilImageMemory);
+
+ // request changing layout with next frame
+ mDepthStencilLayoutChangeNeeded = true;
+}
+
+void SwapchainImpl::GetSwapchainImages()
+{
+ auto device = mDevice.GetVkDevice();
+ if(!mBuffers.empty())
+ {
+ // delete only views, images are discarded by swapchain as swapchain bound resource
+ // we do not discard existing command buffers, no need when replacing swapchain
+ for(auto&& buffer : mBuffers)
+ {
+ device.destroyImageView(buffer.imageView, mDevice.GetVkAllocator());
+ device.destroyFramebuffer(buffer.framebuffer, mDevice.GetVkAllocator());
+ buffer.imageView = nullptr;
+ buffer.framebuffer = nullptr;
+ }
+ }
+
+ // obtain images
+ auto images = device.getSwapchainImagesKHR(mVkSwapchain).value;
+ assert(images.size() == mMaxBufferCount);
+
+ if(mBuffers.empty())
+ {
+ mBuffers.resize(images.size());
+ }
+
+ // generate views and framebuffers
+ for(uint32_t i = 0; i < mBuffers.size(); ++i)
+ {
+ GenerateViewFramebuffer(i, images[i]);
+ }
+}
+
+void SwapchainImpl::GenerateViewFramebuffer(uint32_t bufferIndex, const vk::Image& image)
+{
+ Stack stack(1024);
+ auto& ivInfo = *stack.AllocNew< vk::ImageViewCreateInfo >();
+ ivInfo.components = (*stack.AllocNew< vk::ComponentMapping >())
+ .setR(vk::ComponentSwizzle::eR)
+ .setG(vk::ComponentSwizzle::eG)
+ .setB(vk::ComponentSwizzle::eB)
+ .setA(vk::ComponentSwizzle::eA);
+ ivInfo.viewType = vk::ImageViewType::e2D;
+ ivInfo.image = image;
+ ivInfo.subresourceRange = (*stack.AllocNew< vk::ImageSubresourceRange >())
+ .setLayerCount(1)
+ .setBaseArrayLayer(0)
+ .setBaseMipLevel(0)
+ .setLevelCount(1)
+ .setLayerCount(1)
+ .setAspectMask(vk::ImageAspectFlagBits::eColor);
+ ivInfo.setFormat(mSurface.GetFormat().format);
+
+ auto& fbInfo = *stack.AllocNew< vk::FramebufferCreateInfo >();
+
+ fbInfo.pAttachments = nullptr;
+ fbInfo.attachmentCount = mDepthStencilMode != DepthStencil::NONE ? 2 : 1;
+ fbInfo.renderPass = mRenderPass;
+ fbInfo.layers = 1;
+ fbInfo.width = mSurface.GetWidth();
+ fbInfo.height = mSurface.GetHeight();
+
+ auto& buffer = mBuffers[bufferIndex];
+
+ // create image view
+ buffer.image = image;
+ ivInfo.setImage(buffer.image);
+ VkAssertCall(mDevice.GetVkDevice().createImageView(&ivInfo, mDevice.GetVkAllocator(), &buffer.imageView));
+
+ auto attachments = stack.Alloc< vk::ImageView >(2);
+ attachments[0] = buffer.imageView;
+ attachments[1] = mVkDepthStencilImageView;
+
+ // create framebuffer
+ fbInfo.pAttachments = attachments;
+ VkAssertCall(mDevice.GetVkDevice().createFramebuffer(&fbInfo, mDevice.GetVkAllocator(), &buffer.framebuffer));
+ buffer.layout = vk::ImageLayout::eUndefined;
+}
+
+void SwapchainImpl::CreateMainRenderPass()
+{
+ // Todo: sampling
+ // Todo: stencil
+ // Todo: separate clear if not needed ( however it's better if render pass does clear framebuffer automatically )
+ auto device = mDevice.GetVkDevice();
+ auto allocator = mDevice.GetVkAllocator();
+
+ auto stack = Stack{1024};
+
+ uint32_t attCount = mDepthStencilMode != DepthStencil::NONE ? 2 : 1;
+
+ vk::AttachmentReference attRef[2] = {
+ vk::AttachmentReference().setLayout(vk::ImageLayout::eColorAttachmentOptimal).setAttachment(0),
+ vk::AttachmentReference().setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal).setAttachment(1)};
+
+ auto& subpassDescription = *stack.AllocNew< vk::SubpassDescription >();
+ subpassDescription.setPResolveAttachments(nullptr)
+ .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
+ .setPDepthStencilAttachment(attCount == 2 ? &attRef[1] : nullptr)
+ .setPColorAttachments(&attRef[0])
+ .setColorAttachmentCount(1);
+
+ auto attDesc = stack.Alloc< vk::AttachmentDescription >(2);
+ attDesc[0] = vk::AttachmentDescription()
+ .setFormat(mSurface.GetFormat().format)
+ .setInitialLayout(vk::ImageLayout::eColorAttachmentOptimal)
+ .setSamples(vk::SampleCountFlagBits::e1)
+ .setStoreOp(vk::AttachmentStoreOp::eStore)
+ .setStencilLoadOp(vk::AttachmentLoadOp::eClear)
+ .setLoadOp(vk::AttachmentLoadOp::eClear)
+ .setFinalLayout(vk::ImageLayout::ePresentSrcKHR);
+ attDesc[1] = vk::AttachmentDescription()
+ .setFormat(mDepthStencilFormat)
+ .setInitialLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal)
+ .setSamples(vk::SampleCountFlagBits::e1)
+ .setStoreOp(vk::AttachmentStoreOp::eDontCare)
+ .setStencilLoadOp(vk::AttachmentLoadOp::eClear)
+ .setLoadOp(vk::AttachmentLoadOp::eClear)
+ .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
+
+ auto& rpInfo = stack.AllocNewRef< vk::RenderPassCreateInfo >();
+ rpInfo.setSubpassCount(1).setPSubpasses(&subpassDescription).setAttachmentCount(attCount).setPAttachments(attDesc);
+
+ VkAssertCall(device.createRenderPass(&rpInfo, allocator, &mRenderPass));
+}
+
+void SwapchainImpl::CreateCommandBuffers()
+{
+ auto device = mDevice.GetVkDevice();
+ for(auto&& buffer : mBuffers)
+ {
+ // create command buffer
+ if(!buffer.commandBuffer)
+ {
+ buffer.commandBuffer = mCommandPool.AllocateCommandBuffer(true);
+ }
+
+ // create fence
+ if(!buffer.fence)
+ {
+ vk::FenceCreateInfo info;
+ VkAssertCall(device.createFence(&info, mDevice.GetVkAllocator(), &buffer.fence));
+ }
+ }
+}
+
+void SwapchainImpl::CreateSemaphores()
+{
+ auto device = mDevice.GetVkDevice();
+ if(mAcquireSemaphore.empty())
+ {
+ mAcquireSemaphore.resize(mMaxBufferCount + 1);
+ }
+ if(mPresentSemaphore.empty())
+ {
+ mPresentSemaphore.resize(mMaxBufferCount + 1);
+ }
+
+ vk::SemaphoreCreateInfo info;
+ for(auto&& sem : mAcquireSemaphore)
+ {
+ if(!sem)
+ {
+ VkAssertCall(device.createSemaphore(&info, mDevice.GetVkAllocator(), &sem));
+ }
+ }
+ for(auto&& sem : mPresentSemaphore)
+ {
+ if(!sem)
+ {
+ VkAssertCall(device.createSemaphore(&info, mDevice.GetVkAllocator(), &sem));
+ }
+ }
+}
+
+void SwapchainImpl::BeginFrame()
+{
+ auto& stack = mDevice.GetStack(0);
+ auto frame = stack.Mark();
+
+ auto& swapbuffer = mBuffers[mAcquiredBufferIndex];
+ auto& cmdbuf = swapbuffer.commandBuffer;
+
+ AcquireNextImage();
+
+ cmdbuf.Reset();
+ cmdbuf.Begin(true);
+
+ // change layouts if necessary
+ auto barriers = stack.Alloc< vk::ImageMemoryBarrier >(2);
+ uint32_t barrierIndex = 0;
+ // change depth/stencil attachment layout
+ if(mDepthStencilMode != DepthStencil::NONE && mDepthStencilLayoutChangeNeeded)
+ {
+ RecordDepthStencilBarrier(barriers[barrierIndex++]);
+ mDepthStencilLayoutChangeNeeded = false;
+ }
+
+ // change color attachment layout
+ if(swapbuffer.layout != vk::ImageLayout::eColorAttachmentOptimal)
+ {
+ RecordColorBarrier(barriers[barrierIndex++], swapbuffer);
+ }
+
+ // record pipeline barrier command
+ cmdbuf->pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe,
+ vk::PipelineStageFlagBits::eTopOfPipe, vk::DependencyFlags(), 0, nullptr,
+ 0, nullptr, static_cast< uint32_t >(barrierIndex), &barriers[0]);
+
+ BeginRenderPass(cmdbuf);
+
+ stack.Rollback(frame);
+}
+
+void SwapchainImpl::AcquireNextImage()
+{
+ auto device = mDevice.GetVkDevice();
+ auto semaphore = mAcquireSemaphore[mCurrentBufferIndex];
+ auto& swapbuffer = mBuffers[mAcquiredBufferIndex];
+
+ // acquire new image
+ VkTestCall(device.acquireNextImageKHR(mVkSwapchain, 1000000u, semaphore, nullptr, &mAcquiredBufferIndex));
+
+ // check fence of selected buffer
+ if(swapbuffer.submitted)
+ {
+ // fixme: ugly busy wait which in most of cases should not happen
+
+ while(device.waitForFences(1, &swapbuffer.fence, false, 1000000) != vk::Result::eSuccess)
+ {
+ }
+ }
+ VkAssertCall(device.resetFences(1, &swapbuffer.fence));
+}
+
+void SwapchainImpl::RecordDepthStencilBarrier(vk::ImageMemoryBarrier& barrier)
+{
+ barrier.setImage(*mVkDepthStencilImage)
+ .setSubresourceRange(vk::ImageSubresourceRange()
+ .setLayerCount(1)
+ .setBaseArrayLayer(0)
+ .setBaseMipLevel(0)
+ .setLevelCount(1)
+ .setLayerCount(1)
+ .setAspectMask(vk::ImageAspectFlagBits::eDepth))
+ .setSrcAccessMask(vk::AccessFlagBits())
+ .setDstAccessMask(vk::AccessFlagBits::eDepthStencilAttachmentWrite)
+ .setOldLayout(vk::ImageLayout::eUndefined)
+ .setNewLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
+}
+
+void SwapchainImpl::RecordColorBarrier(vk::ImageMemoryBarrier& barrier, SwapchainFramebuffer& swapbuffer)
+{
+ vk::AccessFlags srcAccess{};
+ if(swapbuffer.layout != vk::ImageLayout::eUndefined)
+ {
+ srcAccess = (vk::AccessFlagBits::eMemoryRead);
+ }
+
+ barrier.setImage(swapbuffer.image)
+ .setSubresourceRange(vk::ImageSubresourceRange()
+ .setLayerCount(1)
+ .setBaseArrayLayer(0)
+ .setBaseMipLevel(0)
+ .setLevelCount(1)
+ .setLayerCount(1)
+ .setAspectMask(vk::ImageAspectFlagBits::eColor))
+ .setSrcAccessMask(srcAccess)
+ .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
+ .setOldLayout(swapbuffer.layout)
+ .setNewLayout(vk::ImageLayout::eColorAttachmentOptimal);
+
+ swapbuffer.layout = vk::ImageLayout::eColorAttachmentOptimal;
+}
+
+void SwapchainImpl::BeginRenderPass(CommandBuffer& cmdbuf)
+{
+ auto& stack = mDevice.GetStack(0);
+ auto frame = stack.Mark();
+
+ auto& swapbuffer = mBuffers[mAcquiredBufferIndex];
+ auto& area = stack.AllocNewRef< vk::Rect2D >();
+ area.setOffset({0, 0}).setExtent({mSurface.GetWidth(), mSurface.GetHeight()});
+
+ // THIS CODE IS VERY TEMPORARY!!!
+ static float red = 0.0f;
+ red += 0.01f;
+ if(red > 1.0f)
+ {
+ red -= 1.0f;
+ }
+
+ // clear values
+ auto clearValues = stack.Alloc< vk::ClearValue >(2);
+
+ // clear color
+ clearValues[0] = vk::ClearValue().color.setFloat32({red, 0.0f, 0.0f, 1.0f});
+
+ // clear depth/stencil
+ clearValues[1] = vk::ClearValue().depthStencil.setDepth(1.0f).setStencil(0);
+
+ // begin main render pass
+ auto& rpInfo = stack.AllocNewRef< vk::RenderPassBeginInfo >();
+ rpInfo.setRenderPass(mRenderPass)
+ .setRenderArea(area)
+ .setPClearValues(clearValues)
+ .setClearValueCount(mDepthStencilMode != DepthStencil::NONE ? 2 : 1)
+ .setFramebuffer(swapbuffer.framebuffer);
+
+ // begin render pass
+ cmdbuf->beginRenderPass(&rpInfo, vk::SubpassContents::eInline);
+
+ stack.Rollback(frame);
+}
+
+void SwapchainImpl::Present()
+{
+ Present(mDevice.GetCommandQueue(0, QueueType::PRESENT));
+}
+
+void SwapchainImpl::Present(const CommandQueue& queue)
+{
+ auto& swapbuffer = mBuffers[mAcquiredBufferIndex];
+ auto& cmdbuf = swapbuffer.commandBuffer;
+
+ cmdbuf->endRenderPass();
+ cmdbuf.End();
+
+ vk::PipelineStageFlags waitFlags = vk::PipelineStageFlagBits::eColorAttachmentOutput;
+
+ // submit command buffer
+ queue.Submit(&cmdbuf, 1, &mAcquireSemaphore[mCurrentBufferIndex], 1, // wait for acquire sem
+ &mPresentSemaphore[mCurrentBufferIndex], 1, // signal present sem
+ &waitFlags, swapbuffer.fence);
+
+ // present
+ vk::PresentInfoKHR presentInfo;
+ presentInfo.setPImageIndices(&mAcquiredBufferIndex)
+ .setPResults(nullptr)
+ .setPSwapchains(&mVkSwapchain)
+ .setSwapchainCount(1)
+ .setWaitSemaphoreCount(1)
+ .setPWaitSemaphores(&mPresentSemaphore[mCurrentBufferIndex]);
+
+ VkAssertCall(queue.GetVkQueue().presentKHR(&presentInfo));
+
+ // set swap buffer image layout manually ( will be changed with end of the render pass automatically )
+ swapbuffer.layout = vk::ImageLayout::ePresentSrcKHR;
+ swapbuffer.submitted = true;
+
+ // increase "logical" buffer
+ mCurrentBufferIndex = (mCurrentBufferIndex + 1) % (mMaxBufferCount + 1);
+}
+
+namespace
+{
+SwapchainImpl* GetImpl(const Swapchain* handle)
+{
+ return static_cast< SwapchainImpl* >(handle->GetObject());
+}
+}
+
+Swapchain Swapchain::New(const LogicalDevice& context, const Vulkan::Surface& surface,
+ uint32_t bufferCount, DepthStencil depthStencil)
+{
+ return Swapchain(new SwapchainImpl(context, surface, bufferCount, depthStencil));
+}
+
+const CommandBuffer& Swapchain::GetCommandBuffer(uint32_t index) const
+{
+ return GetImpl(this)->GetCommandBuffer(index);
+}
+
+const CommandBuffer& Swapchain::GetCurrentCommandBuffer() const
+{
+ return GetImpl(this)->GetCurrentCommandBuffer();
+}
+
+const vk::Image& Swapchain::GetCurrentImage() const
+{
+ return GetImpl(this)->GetCurrentImage();
+}
+
+} // Vulkan
+} // Graphics
+} // Dali
--- /dev/null
+#ifndef DALI_CORE_GRAPHICS_VULKAN_SWAPCHAIN_H
+#define DALI_CORE_GRAPHICS_VULKAN_SWAPCHAIN_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <dali/graphics/graphics-swapchain.h>
+#include <dali/graphics/vulkan/common.h>
+
+namespace Dali
+{
+namespace Graphics
+{
+namespace Vulkan
+{
+
+class Surface;
+class LogicalDevice;
+class CommandBuffer;
+
+/**
+ * In computer graphics swap chain represents a series of images which are sort of
+ * virtual framebuffers.
+ * Swapchain class manages mentioned images ( swaps them when needed for example on vsync )
+ * and delivers an image to the graphics API as a render target bound to
+ * the surface ( simplifying, delivers main framebuffer to render to ).
+ */
+class Swapchain : public GraphicsSwapchain
+{
+public:
+ Swapchain(Integration::GraphicsSwapchainBase* impl = nullptr) : GraphicsSwapchain{impl}
+ {
+ }
+
+ using GraphicsSwapchain::operator=;
+
+ static Swapchain New(const LogicalDevice& device, const Surface& surface, uint32_t bufferCount,
+ DepthStencil depthStencil);
+
+ const CommandBuffer& GetCommandBuffer(uint32_t index) const;
+
+ const CommandBuffer& GetCurrentCommandBuffer() const;
+
+ const vk::Image& GetCurrentImage() const;
+};
+
+} // Vulkan
+} // Graphics
+} // Dali
+
+#endif //DALI_CORE_GRAPHICS_VULKAN_SWAPCHAIN_H