Commit 4d0bf557 by Jamie Madill Committed by Commit Bot

Vulkan: Initialize the draw surface.

This also involves initializing the swap chain and queue. BUG=angleproject:1319 Change-Id: Ia3a2141905f17b2cdddddab07336f33a737d4fc1 Reviewed-on: https://chromium-review.googlesource.com/367752Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent d7c5b0aa
...@@ -111,6 +111,11 @@ Error::Error(EGLint errorCode, EGLint id, const char *msg, ...) : mCode(errorCod ...@@ -111,6 +111,11 @@ Error::Error(EGLint errorCode, EGLint id, const char *msg, ...) : mCode(errorCod
va_end(vararg); va_end(vararg);
} }
Error::Error(EGLint errorCode, EGLint id, const std::string &msg)
: mCode(errorCode), mID(id), mMessage(new std::string(msg))
{
}
void Error::createMessageString() const void Error::createMessageString() const
{ {
if (!mMessage) if (!mMessage)
......
...@@ -16,11 +16,33 @@ ...@@ -16,11 +16,33 @@
#include <string> #include <string>
#include <memory> #include <memory>
namespace gl namespace angle
{
template <typename ErrorT, typename ResultT, typename ErrorBaseT, ErrorBaseT NoErrorVal>
class ErrorOrResultBase
{ {
public:
ErrorOrResultBase(const ErrorT &error) : mError(error) {}
ErrorOrResultBase(ErrorT &&error) : mError(std::move(error)) {}
template <typename T> ErrorOrResultBase(ResultT &&result) : mError(NoErrorVal), mResult(std::forward<ResultT>(result))
class ErrorOrResult; {
}
ErrorOrResultBase(const ResultT &result) : mError(NoErrorVal), mResult(result) {}
bool isError() const { return mError.isError(); }
const ErrorT &getError() const { return mError; }
ResultT &&getResult() { return std::move(mResult); }
private:
ErrorT mError;
ResultT mResult;
};
} // namespace angle
namespace gl
{
class Error final class Error final
{ {
...@@ -53,6 +75,9 @@ class Error final ...@@ -53,6 +75,9 @@ class Error final
mutable std::unique_ptr<std::string> mMessage; mutable std::unique_ptr<std::string> mMessage;
}; };
template <typename ResultT>
using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, GLenum, GL_NO_ERROR>;
namespace priv namespace priv
{ {
template <GLenum EnumT> template <GLenum EnumT>
...@@ -110,32 +135,6 @@ ErrorStream<EnumT> &ErrorStream<EnumT>::operator<<(T value) ...@@ -110,32 +135,6 @@ ErrorStream<EnumT> &ErrorStream<EnumT>::operator<<(T value)
using OutOfMemory = priv::ErrorStream<GL_OUT_OF_MEMORY>; using OutOfMemory = priv::ErrorStream<GL_OUT_OF_MEMORY>;
using InternalError = priv::ErrorStream<GL_INVALID_OPERATION>; using InternalError = priv::ErrorStream<GL_INVALID_OPERATION>;
template <typename T>
class ErrorOrResult
{
public:
ErrorOrResult(const gl::Error &error) : mError(error) {}
ErrorOrResult(gl::Error &&error) : mError(std::move(error)) {}
ErrorOrResult(T &&result)
: mError(GL_NO_ERROR), mResult(std::forward<T>(result))
{
}
ErrorOrResult(const T &result)
: mError(GL_NO_ERROR), mResult(result)
{
}
bool isError() const { return mError.isError(); }
const gl::Error &getError() const { return mError; }
T &&getResult() { return std::move(mResult); }
private:
Error mError;
T mResult;
};
inline Error NoError() inline Error NoError()
{ {
return Error(GL_NO_ERROR); return Error(GL_NO_ERROR);
...@@ -152,6 +151,7 @@ class Error final ...@@ -152,6 +151,7 @@ class Error final
explicit inline Error(EGLint errorCode); explicit inline Error(EGLint errorCode);
Error(EGLint errorCode, const char *msg, ...); Error(EGLint errorCode, const char *msg, ...);
Error(EGLint errorCode, EGLint id, const char *msg, ...); Error(EGLint errorCode, EGLint id, const char *msg, ...);
Error(EGLint errorCode, EGLint id, const std::string &msg);
inline Error(const Error &other); inline Error(const Error &other);
inline Error(Error &&other); inline Error(Error &&other);
...@@ -177,6 +177,9 @@ inline Error NoError() ...@@ -177,6 +177,9 @@ inline Error NoError()
return Error(EGL_SUCCESS); return Error(EGL_SUCCESS);
} }
template <typename ResultT>
using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, EGLint, EGL_SUCCESS>;
} // namespace egl } // namespace egl
#define ANGLE_CONCAT1(x, y) x##y #define ANGLE_CONCAT1(x, y) x##y
......
...@@ -110,8 +110,13 @@ bool DisplayVk::isValidNativeWindow(EGLNativeWindowType window) const ...@@ -110,8 +110,13 @@ bool DisplayVk::isValidNativeWindow(EGLNativeWindowType window) const
std::string DisplayVk::getVendorString() const std::string DisplayVk::getVendorString() const
{ {
// TODO(jmadill): Determine GPU vendor from Renderer. std::string vendorString = "Google Inc.";
return std::string("Google Inc."); if (mRenderer)
{
vendorString += " " + mRenderer->getVendorString();
}
return vendorString;
} }
egl::Error DisplayVk::getDevice(DeviceImpl **device) egl::Error DisplayVk::getDevice(DeviceImpl **device)
...@@ -137,7 +142,10 @@ SurfaceImpl *DisplayVk::createWindowSurface(const egl::SurfaceState &state, ...@@ -137,7 +142,10 @@ SurfaceImpl *DisplayVk::createWindowSurface(const egl::SurfaceState &state,
EGLNativeWindowType window, EGLNativeWindowType window,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
return new WindowSurfaceVk(state, window); EGLint width = attribs.getAsInt(EGL_WIDTH, 0);
EGLint height = attribs.getAsInt(EGL_HEIGHT, 0);
return new WindowSurfaceVk(state, window, width, height);
} }
SurfaceImpl *DisplayVk::createPbufferSurface(const egl::SurfaceState &state, SurfaceImpl *DisplayVk::createPbufferSurface(const egl::SurfaceState &state,
......
...@@ -69,6 +69,8 @@ class DisplayVk : public DisplayImpl ...@@ -69,6 +69,8 @@ class DisplayVk : public DisplayImpl
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
gl::Version getMaxSupportedESVersion() const override; gl::Version getMaxSupportedESVersion() const override;
RendererVk *getRenderer() const { return mRenderer.get(); }
private: private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override; void generateCaps(egl::Caps *outCaps) const override;
......
...@@ -9,9 +9,13 @@ ...@@ -9,9 +9,13 @@
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
// Placing this first seems to solve an intellisense bug.
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/renderer/driver_utils.h"
#include "libANGLE/renderer/vulkan/CompilerVk.h" #include "libANGLE/renderer/vulkan/CompilerVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h" #include "libANGLE/renderer/vulkan/TextureVk.h"
...@@ -80,12 +84,31 @@ RendererVk::RendererVk() ...@@ -80,12 +84,31 @@ RendererVk::RendererVk()
: mCapsInitialized(false), : mCapsInitialized(false),
mInstance(VK_NULL_HANDLE), mInstance(VK_NULL_HANDLE),
mEnableValidationLayers(false), mEnableValidationLayers(false),
mDebugReportCallback(VK_NULL_HANDLE) mDebugReportCallback(VK_NULL_HANDLE),
mPhysicalDevice(VK_NULL_HANDLE),
mQueue(VK_NULL_HANDLE),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mDevice(VK_NULL_HANDLE),
mCommandPool(VK_NULL_HANDLE)
{ {
} }
RendererVk::~RendererVk() RendererVk::~RendererVk()
{ {
mCommandBuffer.reset(nullptr);
if (mCommandPool)
{
vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
mCommandPool = VK_NULL_HANDLE;
}
if (mDevice)
{
vkDestroyDevice(mDevice, nullptr);
mDevice = VK_NULL_HANDLE;
}
if (mDebugReportCallback) if (mDebugReportCallback)
{ {
ASSERT(mInstance); ASSERT(mInstance);
...@@ -95,7 +118,13 @@ RendererVk::~RendererVk() ...@@ -95,7 +118,13 @@ RendererVk::~RendererVk()
destroyDebugReportCallback(mInstance, mDebugReportCallback, nullptr); destroyDebugReportCallback(mInstance, mDebugReportCallback, nullptr);
} }
if (mInstance)
{
vkDestroyInstance(mInstance, nullptr); vkDestroyInstance(mInstance, nullptr);
mInstance = VK_NULL_HANDLE;
}
mPhysicalDevice = VK_NULL_HANDLE;
} }
vk::Error RendererVk::initialize(const egl::AttributeMap &attribs) vk::Error RendererVk::initialize(const egl::AttributeMap &attribs)
...@@ -213,13 +242,216 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs) ...@@ -213,13 +242,216 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs)
createDebugReportCallback(mInstance, &debugReportInfo, nullptr, &mDebugReportCallback)); createDebugReportCallback(mInstance, &debugReportInfo, nullptr, &mDebugReportCallback));
} }
uint32_t physicalDeviceCount = 0;
ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
ANGLE_VK_CHECK(physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
// TODO(jmadill): Handle multiple physical devices. For now, use the first device.
physicalDeviceCount = 1;
ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, &mPhysicalDevice));
vkGetPhysicalDeviceProperties(mPhysicalDevice, &mPhysicalDeviceProperties);
// Ensure we can find a graphics queue family.
uint32_t queueCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
ANGLE_VK_CHECK(queueCount > 0, VK_ERROR_INITIALIZATION_FAILED);
mQueueFamilyProperties.resize(queueCount);
vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount,
mQueueFamilyProperties.data());
size_t graphicsQueueFamilyCount = false;
uint32_t firstGraphicsQueueFamily = 0;
for (uint32_t familyIndex = 0; familyIndex < queueCount; ++familyIndex)
{
const auto &queueInfo = mQueueFamilyProperties[familyIndex];
if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
{
ASSERT(queueInfo.queueCount > 0);
graphicsQueueFamilyCount++;
if (firstGraphicsQueueFamily == 0)
{
firstGraphicsQueueFamily = familyIndex;
}
break;
}
}
ANGLE_VK_CHECK(graphicsQueueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED);
// If only one queue family, go ahead and initialize the device. If there is more than one
// queue, we'll have to wait until we see a WindowSurface to know which supports present.
if (graphicsQueueFamilyCount == 1)
{
ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
}
return vk::NoError(); return vk::NoError();
} }
vk::Error RendererVk::initializeDevice(uint32_t queueFamilyIndex)
{
uint32_t deviceLayerCount = 0;
ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, nullptr));
std::vector<VkLayerProperties> deviceLayerProps(deviceLayerCount);
if (deviceLayerCount > 0)
{
ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount,
deviceLayerProps.data()));
}
uint32_t deviceExtensionCount = 0;
ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
&deviceExtensionCount, nullptr));
std::vector<VkExtensionProperties> deviceExtensionProps(deviceExtensionCount);
if (deviceExtensionCount > 0)
{
ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(
mPhysicalDevice, nullptr, &deviceExtensionCount, deviceExtensionProps.data()));
}
if (mEnableValidationLayers)
{
if (!HasStandardValidationLayer(deviceLayerProps))
{
ANGLEPlatformCurrent()->logWarning("Vulkan standard validation layer is missing.");
mEnableValidationLayers = false;
}
}
std::vector<const char *> enabledDeviceExtensions;
enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
ANGLE_VK_TRY(VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
VkDeviceQueueCreateInfo queueCreateInfo;
float zeroPriority = 0.0f;
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.pNext = nullptr;
queueCreateInfo.flags = 0;
queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &zeroPriority;
// Initialize the device
VkDeviceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.queueCreateInfoCount = 1;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
createInfo.ppEnabledLayerNames =
mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
createInfo.ppEnabledExtensionNames =
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
createInfo.pEnabledFeatures = nullptr; // TODO(jmadill): features
ANGLE_VK_TRY(vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
mCurrentQueueFamilyIndex = queueFamilyIndex;
vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue);
// Initialize the command pool now that we know the queue family index.
VkCommandPoolCreateInfo commandPoolInfo;
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolInfo.pNext = nullptr;
// TODO(jmadill): Investigate transient command buffers.
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
commandPoolInfo.queueFamilyIndex = mCurrentQueueFamilyIndex;
ANGLE_VK_TRY(vkCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool));
mCommandBuffer.reset(new vk::CommandBuffer(mDevice, mCommandPool));
return vk::NoError();
}
vk::ErrorOrResult<uint32_t> RendererVk::selectPresentQueueForSurface(VkSurfaceKHR surface)
{
// We've already initialized a device, and can't re-create it unless it's never been used.
// TODO(jmadill): Handle the re-creation case if necessary.
if (mDevice != VK_NULL_HANDLE)
{
ASSERT(mCurrentQueueFamilyIndex != std::numeric_limits<uint32_t>::max());
// Check if the current device supports present on this surface.
VkBool32 supportsPresent = VK_FALSE;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, mCurrentQueueFamilyIndex,
surface, &supportsPresent));
return (supportsPresent == VK_TRUE);
}
// Find a graphics and present queue.
Optional<uint32_t> newPresentQueue;
uint32_t queueCount = static_cast<uint32_t>(mQueueFamilyProperties.size());
for (uint32_t queueIndex = 0; queueIndex < queueCount; ++queueIndex)
{
const auto &queueInfo = mQueueFamilyProperties[queueIndex];
if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
{
VkBool32 supportsPresent = VK_FALSE;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, queueIndex, surface,
&supportsPresent));
if (supportsPresent == VK_TRUE)
{
newPresentQueue = queueIndex;
break;
}
}
}
ANGLE_VK_CHECK(newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED);
ANGLE_TRY(initializeDevice(newPresentQueue.value()));
return newPresentQueue.value();
}
std::string RendererVk::getVendorString() const
{
switch (mPhysicalDeviceProperties.vendorID)
{
case VENDOR_ID_AMD:
return "Advanced Micro Devices";
case VENDOR_ID_NVIDIA:
return "NVIDIA";
case VENDOR_ID_INTEL:
return "Intel";
default:
{
// TODO(jmadill): More vendor IDs.
std::stringstream strstr;
strstr << "Vendor ID: " << mPhysicalDeviceProperties.vendorID;
return strstr.str();
}
}
}
std::string RendererVk::getRendererDescription() const std::string RendererVk::getRendererDescription() const
{ {
// TODO(jmadill): Description. std::stringstream strstr;
return "Vulkan";
uint32_t apiVersion = mPhysicalDeviceProperties.apiVersion;
strstr << "Vulkan ";
strstr << VK_VERSION_MAJOR(apiVersion) << ".";
strstr << VK_VERSION_MINOR(apiVersion) << ".";
strstr << VK_VERSION_PATCH(apiVersion);
strstr << "(" << mPhysicalDeviceProperties.deviceName << ")";
return strstr.str();
} }
void RendererVk::ensureCapsInitialized() const void RendererVk::ensureCapsInitialized() const
...@@ -263,4 +495,38 @@ const gl::Limitations &RendererVk::getNativeLimitations() const ...@@ -263,4 +495,38 @@ const gl::Limitations &RendererVk::getNativeLimitations() const
return mNativeLimitations; return mNativeLimitations;
} }
vk::CommandBuffer *RendererVk::getCommandBuffer()
{
return mCommandBuffer.get();
}
vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer)
{
VkFenceCreateInfo fenceInfo;
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.pNext = nullptr;
fenceInfo.flags = 0;
VkCommandBuffer commandBufferHandle = commandBuffer.getHandle();
VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pWaitSemaphores = nullptr;
submitInfo.pWaitDstStageMask = nullptr;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBufferHandle;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = nullptr;
// TODO(jmadill): Investigate how to properly submit command buffers.
ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
// Wait indefinitely for the queue to finish.
ANGLE_VK_TRY(vkQueueWaitIdle(mQueue));
return vk::NoError();
}
} // namespace rx } // namespace rx
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_ #ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
#define LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_ #define LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
#include <memory>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "common/angleutils.h" #include "common/angleutils.h"
...@@ -32,9 +33,18 @@ class RendererVk : angle::NonCopyable ...@@ -32,9 +33,18 @@ class RendererVk : angle::NonCopyable
vk::Error initialize(const egl::AttributeMap &attribs); vk::Error initialize(const egl::AttributeMap &attribs);
std::string getVendorString() const;
std::string getRendererDescription() const; std::string getRendererDescription() const;
VkInstance getInstance() const { return mInstance; } VkInstance getInstance() const { return mInstance; }
VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; }
VkDevice getDevice() const { return mDevice; }
vk::ErrorOrResult<uint32_t> selectPresentQueueForSurface(VkSurfaceKHR surface);
// TODO(jmadill): Use ContextImpl for command buffers to enable threaded contexts.
vk::CommandBuffer *getCommandBuffer();
vk::Error submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer);
const gl::Caps &getNativeCaps() const; const gl::Caps &getNativeCaps() const;
const gl::TextureCapsMap &getNativeTextureCaps() const; const gl::TextureCapsMap &getNativeTextureCaps() const;
...@@ -54,9 +64,19 @@ class RendererVk : angle::NonCopyable ...@@ -54,9 +64,19 @@ class RendererVk : angle::NonCopyable
mutable gl::Extensions mNativeExtensions; mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations; mutable gl::Limitations mNativeLimitations;
vk::Error initializeDevice(uint32_t queueFamilyIndex);
VkInstance mInstance; VkInstance mInstance;
bool mEnableValidationLayers; bool mEnableValidationLayers;
VkDebugReportCallbackEXT mDebugReportCallback; VkDebugReportCallbackEXT mDebugReportCallback;
VkPhysicalDevice mPhysicalDevice;
VkPhysicalDeviceProperties mPhysicalDeviceProperties;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
VkQueue mQueue;
uint32_t mCurrentQueueFamilyIndex;
VkDevice mDevice;
VkCommandPool mCommandPool;
std::unique_ptr<vk::CommandBuffer> mCommandBuffer;
}; };
} // namespace rx } // namespace rx
......
...@@ -10,12 +10,25 @@ ...@@ -10,12 +10,25 @@
#include "libANGLE/renderer/vulkan/SurfaceVk.h" #include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx namespace rx
{ {
namespace
{
VkFormat GetVkFormatFromConfig(const egl::Config &config)
{
// TODO(jmadill): Properly handle format interpretation.
return VK_FORMAT_B8G8R8A8_UNORM;
}
} // namespace
OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState,
EGLint width, EGLint width,
EGLint height) EGLint height)
...@@ -98,19 +111,233 @@ gl::Error OffscreenSurfaceVk::getAttachmentRenderTarget( ...@@ -98,19 +111,233 @@ gl::Error OffscreenSurfaceVk::getAttachmentRenderTarget(
return gl::Error(GL_INVALID_OPERATION); return gl::Error(GL_INVALID_OPERATION);
} }
WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window) WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
: SurfaceImpl(surfaceState) EGLNativeWindowType window,
EGLint width,
EGLint height)
: SurfaceImpl(surfaceState),
mNativeWindowType(window),
mWidth(width),
mHeight(height),
mSurface(VK_NULL_HANDLE),
mSwapchain(VK_NULL_HANDLE),
mDevice(VK_NULL_HANDLE),
mInstance(VK_NULL_HANDLE)
{ {
} }
WindowSurfaceVk::~WindowSurfaceVk() WindowSurfaceVk::~WindowSurfaceVk()
{ {
mSwapchainImages.clear();
if (mSwapchain)
{
vkDestroySwapchainKHR(mDevice, mSwapchain, nullptr);
mSwapchain = VK_NULL_HANDLE;
}
if (mSurface)
{
vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
mSurface = VK_NULL_HANDLE;
}
} }
egl::Error WindowSurfaceVk::initialize(const DisplayImpl *displayImpl) egl::Error WindowSurfaceVk::initialize(const DisplayImpl *displayImpl)
{ {
// TODO(jmadill) const DisplayVk *displayVk = GetAs<DisplayVk>(displayImpl);
return egl::Error(EGL_SUCCESS); return initializeImpl(displayVk->getRenderer()).toEGL(EGL_BAD_SURFACE);
}
vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
{
// These are needed for resource deallocation.
// TODO(jmadill): Don't cache these.
mDevice = renderer->getDevice();
mInstance = renderer->getInstance();
// TODO(jmadill): Make this platform-specific.
VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.hinstance = GetModuleHandle(nullptr);
createInfo.hwnd = mNativeWindowType;
ANGLE_VK_TRY(vkCreateWin32SurfaceKHR(renderer->getInstance(), &createInfo, nullptr, &mSurface));
uint32_t presentQueue = 0;
ANGLE_TRY_RESULT(renderer->selectPresentQueueForSurface(mSurface), presentQueue);
const auto &physicalDevice = renderer->getPhysicalDevice();
VkSurfaceCapabilitiesKHR surfaceCaps;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &surfaceCaps));
// Adjust width and height to the swapchain if necessary.
if (surfaceCaps.currentExtent.width != 0xFFFFFFFFu)
{
ASSERT(surfaceCaps.currentExtent.height != 0xFFFFFFFFu);
mWidth = static_cast<EGLint>(surfaceCaps.currentExtent.width);
mHeight = static_cast<EGLint>(surfaceCaps.currentExtent.height);
}
else
{
ASSERT(surfaceCaps.currentExtent.height == 0xFFFFFFFFu);
RECT rect;
ANGLE_VK_CHECK(GetClientRect(mNativeWindowType, &rect) == TRUE,
VK_ERROR_INITIALIZATION_FAILED);
if (mWidth == 0)
{
mWidth = static_cast<EGLint>(rect.right - rect.left);
}
if (mHeight == 0)
{
mHeight = static_cast<EGLint>(rect.bottom - rect.top);
}
}
uint32_t presentModeCount = 0;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
&presentModeCount, nullptr));
ASSERT(presentModeCount > 0);
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
&presentModeCount, presentModes.data()));
// Use FIFO mode if available, since it throttles you to the display rate. Mailbox can lead
// to rendering frames which are never seen by the user, wasting power.
VkPresentModeKHR swapchainPresentMode = presentModes[0];
for (auto presentMode : presentModes)
{
if (presentMode == VK_PRESENT_MODE_FIFO_KHR)
{
swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
break;
}
// Fallback to immediate mode if FIFO is unavailable.
if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
{
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
// Determine number of swapchain images. Aim for one more than the minimum.
uint32_t minImageCount = surfaceCaps.minImageCount + 1;
if (surfaceCaps.maxImageCount > 0 && minImageCount > surfaceCaps.maxImageCount)
{
minImageCount = surfaceCaps.maxImageCount;
}
// Default to identity transform.
VkSurfaceTransformFlagBitsKHR preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
if ((surfaceCaps.supportedTransforms & preTransform) == 0)
{
preTransform = surfaceCaps.currentTransform;
}
VkFormat configSurfaceFormat = GetVkFormatFromConfig(*mState.config);
uint32_t surfaceFormatCount = 0;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
nullptr));
std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
surfaceFormats.data()));
if (surfaceFormatCount == 1u && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
{
// This is fine.
}
else
{
bool foundFormat = false;
for (const auto &surfaceFormat : surfaceFormats)
{
if (surfaceFormat.format == configSurfaceFormat)
{
foundFormat = true;
break;
}
}
ANGLE_VK_CHECK(foundFormat, VK_ERROR_INITIALIZATION_FAILED);
}
VkSwapchainCreateInfoKHR swapchainInfo;
swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainInfo.pNext = nullptr;
swapchainInfo.flags = 0;
swapchainInfo.surface = mSurface;
swapchainInfo.minImageCount = minImageCount;
swapchainInfo.imageFormat = configSurfaceFormat;
swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swapchainInfo.imageExtent.width = mWidth;
swapchainInfo.imageExtent.height = mHeight;
swapchainInfo.imageArrayLayers = 1;
swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainInfo.queueFamilyIndexCount = 0;
swapchainInfo.pQueueFamilyIndices = nullptr;
swapchainInfo.preTransform = preTransform;
swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapchainInfo.presentMode = swapchainPresentMode;
swapchainInfo.clipped = VK_TRUE;
swapchainInfo.oldSwapchain = VK_NULL_HANDLE;
const auto &device = renderer->getDevice();
ANGLE_VK_TRY(vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &mSwapchain));
// Intialize the swapchain image views.
uint32_t imageCount = 0;
ANGLE_VK_TRY(vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, nullptr));
std::vector<VkImage> swapchainImages(imageCount);
ANGLE_VK_TRY(vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
// CommandBuffer is a singleton in the Renderer.
vk::CommandBuffer *commandBuffer = renderer->getCommandBuffer();
ANGLE_TRY(commandBuffer->begin());
for (auto swapchainImage : swapchainImages)
{
VkImageViewCreateInfo imageViewInfo;
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewInfo.pNext = nullptr;
imageViewInfo.flags = 0;
imageViewInfo.image = swapchainImage;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = configSurfaceFormat;
imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewInfo.subresourceRange.baseMipLevel = 0;
imageViewInfo.subresourceRange.levelCount = 1;
imageViewInfo.subresourceRange.baseArrayLayer = 0;
imageViewInfo.subresourceRange.layerCount = 1;
vk::Image image(swapchainImage);
vk::ImageView imageView(device);
ANGLE_TRY(imageView.init(imageViewInfo));
// Set optimal color layout for the image.
image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
commandBuffer);
mSwapchainImages.push_back(std::move(image));
mSwapchainImageViews.push_back(std::move(imageView));
}
ANGLE_TRY(commandBuffer->end());
ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer));
return vk::NoError();
} }
FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state) FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state)
...@@ -152,14 +379,12 @@ void WindowSurfaceVk::setSwapInterval(EGLint interval) ...@@ -152,14 +379,12 @@ void WindowSurfaceVk::setSwapInterval(EGLint interval)
EGLint WindowSurfaceVk::getWidth() const EGLint WindowSurfaceVk::getWidth() const
{ {
// TODO(jmadill) return mWidth;
return 0;
} }
EGLint WindowSurfaceVk::getHeight() const EGLint WindowSurfaceVk::getHeight() const
{ {
// TODO(jmadill) return mHeight;
return 0;
} }
EGLint WindowSurfaceVk::isPostSubBufferSupported() const EGLint WindowSurfaceVk::isPostSubBufferSupported() const
......
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
#ifndef LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_ #ifndef LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
#define LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_ #define LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/SurfaceImpl.h" #include "libANGLE/renderer/SurfaceImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
namespace rx namespace rx
{ {
...@@ -49,7 +52,10 @@ class OffscreenSurfaceVk : public SurfaceImpl ...@@ -49,7 +52,10 @@ class OffscreenSurfaceVk : public SurfaceImpl
class WindowSurfaceVk : public SurfaceImpl class WindowSurfaceVk : public SurfaceImpl
{ {
public: public:
WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window); WindowSurfaceVk(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window,
EGLint width,
EGLint height);
~WindowSurfaceVk() override; ~WindowSurfaceVk() override;
egl::Error initialize(const DisplayImpl *displayImpl) override; egl::Error initialize(const DisplayImpl *displayImpl) override;
...@@ -70,6 +76,24 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -70,6 +76,24 @@ class WindowSurfaceVk : public SurfaceImpl
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
FramebufferAttachmentRenderTarget **rtOut) override; FramebufferAttachmentRenderTarget **rtOut) override;
private:
vk::Error initializeImpl(RendererVk *renderer);
vk::Error nextSwapchainImage(RendererVk *renderer);
vk::Error swapImpl(RendererVk *renderer);
EGLNativeWindowType mNativeWindowType;
EGLint mWidth;
EGLint mHeight;
VkSurfaceKHR mSurface;
VkSwapchainKHR mSwapchain;
// These are needed for resource deallocation.
// TODO(jmadill): Don't store these here.
VkDevice mDevice;
VkInstance mInstance;
std::vector<vk::Image> mSwapchainImages;
std::vector<vk::ImageView> mSwapchainImageViews;
}; };
} // namespace rx } // namespace rx
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "renderervk_utils.h" #include "renderervk_utils.h"
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx namespace rx
{ {
...@@ -46,6 +47,28 @@ EGLint DefaultEGLErrorCode(VkResult result) ...@@ -46,6 +47,28 @@ EGLint DefaultEGLErrorCode(VkResult result)
return EGL_BAD_ACCESS; return EGL_BAD_ACCESS;
} }
} }
// Gets access flags that are common between source and dest layouts.
VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout)
{
switch (layout)
{
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
return VK_ACCESS_TRANSFER_WRITE_BIT;
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
return VK_ACCESS_MEMORY_READ_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
return VK_ACCESS_TRANSFER_READ_BIT;
case VK_IMAGE_LAYOUT_UNDEFINED:
return 0;
default:
// TODO(jmadill): Investigate other flags.
UNREACHABLE();
return 0;
}
}
} // anonymous namespace } // anonymous namespace
// Mirrors std_validation_str in loader.h // Mirrors std_validation_str in loader.h
...@@ -116,6 +139,11 @@ const char *VulkanResultString(VkResult result) ...@@ -116,6 +139,11 @@ const char *VulkanResultString(VkResult result)
namespace vk namespace vk
{ {
Error::Error(VkResult result) : mResult(result), mFile(nullptr), mLine(0)
{
ASSERT(result == VK_SUCCESS);
}
Error::Error(VkResult result, const char *file, unsigned int line) Error::Error(VkResult result, const char *file, unsigned int line)
: mResult(result), mFile(file), mLine(line) : mResult(result), mFile(file), mLine(line)
{ {
...@@ -175,6 +203,198 @@ bool Error::isError() const ...@@ -175,6 +203,198 @@ bool Error::isError() const
return (mResult != VK_SUCCESS); return (mResult != VK_SUCCESS);
} }
// CommandBuffer implementation.
CommandBuffer::CommandBuffer(VkDevice device, VkCommandPool commandPool)
: WrappedObject(device), mCommandPool(commandPool)
{
}
Error CommandBuffer::begin()
{
if (mHandle == VK_NULL_HANDLE)
{
ASSERT(validDevice());
VkCommandBufferAllocateInfo commandBufferInfo;
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferInfo.pNext = nullptr;
commandBufferInfo.commandPool = mCommandPool;
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferInfo.commandBufferCount = 1;
ANGLE_VK_TRY(vkAllocateCommandBuffers(mDevice, &commandBufferInfo, &mHandle));
}
else
{
reset();
}
VkCommandBufferBeginInfo beginInfo;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.pNext = nullptr;
// TODO(jmadill): Use other flags?
beginInfo.flags = 0;
beginInfo.pInheritanceInfo = nullptr;
ANGLE_VK_TRY(vkBeginCommandBuffer(mHandle, &beginInfo));
return NoError();
}
Error CommandBuffer::end()
{
ASSERT(valid());
ANGLE_VK_TRY(vkEndCommandBuffer(mHandle));
return NoError();
}
Error CommandBuffer::reset()
{
ASSERT(valid());
ANGLE_VK_TRY(vkResetCommandBuffer(mHandle, 0));
return NoError();
}
void CommandBuffer::singleImageBarrier(VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
const VkImageMemoryBarrier &imageMemoryBarrier)
{
ASSERT(valid());
vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0,
nullptr, 1, &imageMemoryBarrier);
}
CommandBuffer::~CommandBuffer()
{
if (mHandle)
{
ASSERT(validDevice());
vkFreeCommandBuffers(mDevice, mCommandPool, 1, &mHandle);
}
}
// Image implementation.
Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{
}
Image::Image(VkImage image) : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{
mHandle = image;
}
Image::Image(Image &&other) : WrappedObject(std::move(other)), mCurrentLayout(other.mCurrentLayout)
{
other.mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
Image &Image::operator=(Image &&other)
{
assignOpBase(std::move(other));
std::swap(mCurrentLayout, other.mCurrentLayout);
return *this;
}
Image::~Image()
{
// If the device handle is null, we aren't managing the handle.
if (valid())
{
vkDestroyImage(mDevice, mHandle, nullptr);
}
}
void Image::changeLayout(VkImageAspectFlags aspectMask,
VkImageLayout newLayout,
CommandBuffer *commandBuffer)
{
if (newLayout == mCurrentLayout)
{
// No-op.
return;
}
VkImageMemoryBarrier imageMemoryBarrier;
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.pNext = nullptr;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = 0;
imageMemoryBarrier.oldLayout = mCurrentLayout;
imageMemoryBarrier.newLayout = newLayout;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.image = mHandle;
// TODO(jmadill): Is this needed for mipped/layer images?
imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
// TODO(jmadill): Test all the permutations of the access flags.
imageMemoryBarrier.srcAccessMask = GetBasicLayoutAccessFlags(mCurrentLayout);
if (mCurrentLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
{
imageMemoryBarrier.srcAccessMask |= VK_ACCESS_HOST_WRITE_BIT;
}
imageMemoryBarrier.dstAccessMask = GetBasicLayoutAccessFlags(newLayout);
if (newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
imageMemoryBarrier.srcAccessMask |=
(VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
imageMemoryBarrier.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
}
if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
imageMemoryBarrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
commandBuffer->singleImageBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, imageMemoryBarrier);
mCurrentLayout = newLayout;
}
// ImageView implementation.
ImageView::ImageView()
{
}
ImageView::ImageView(VkDevice device) : WrappedObject(device)
{
}
ImageView::ImageView(ImageView &&other) : WrappedObject(std::move(other))
{
}
ImageView &ImageView::operator=(ImageView &&other)
{
assignOpBase(std::move(other));
return *this;
}
ImageView::~ImageView()
{
if (mHandle != VK_NULL_HANDLE)
{
ASSERT(validDevice());
vkDestroyImageView(mDevice, mHandle, nullptr);
}
}
Error ImageView::init(const VkImageViewCreateInfo &createInfo)
{
ASSERT(validDevice());
ANGLE_VK_TRY(vkCreateImageView(mDevice, &createInfo, nullptr, &mHandle));
return NoError();
}
} // namespace vk } // namespace vk
bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps) bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps)
......
...@@ -28,6 +28,7 @@ namespace vk ...@@ -28,6 +28,7 @@ namespace vk
class Error final class Error final
{ {
public: public:
Error(VkResult result);
Error(VkResult result, const char *file, unsigned int line); Error(VkResult result, const char *file, unsigned int line);
~Error(); ~Error();
...@@ -50,12 +51,96 @@ class Error final ...@@ -50,12 +51,96 @@ class Error final
unsigned int mLine; unsigned int mLine;
}; };
template <typename ResultT>
using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, VkResult, VK_SUCCESS>;
// Avoid conflicting with X headers which define "Success". // Avoid conflicting with X headers which define "Success".
inline Error NoError() inline Error NoError()
{ {
return Error(VK_SUCCESS, nullptr, 0); return Error(VK_SUCCESS);
} }
template <typename HandleT>
class WrappedObject : angle::NonCopyable
{
public:
WrappedObject() : mDevice(VK_NULL_HANDLE), mHandle(VK_NULL_HANDLE) {}
explicit WrappedObject(VkDevice device) : mDevice(device), mHandle(VK_NULL_HANDLE) {}
WrappedObject(WrappedObject &&other) : mDevice(other.mDevice), mHandle(other.mHandle)
{
other.mDevice = VK_NULL_HANDLE;
other.mHandle = VK_NULL_HANDLE;
}
virtual ~WrappedObject() {}
HandleT getHandle() const { return mHandle; }
bool validDevice() const { return (mDevice != VK_NULL_HANDLE); }
bool valid() const { return (mHandle != VK_NULL_HANDLE) && validDevice(); }
protected:
void assignOpBase(WrappedObject &&other)
{
std::swap(mDevice, other.mDevice);
std::swap(mHandle, other.mHandle);
}
VkDevice mDevice;
HandleT mHandle;
};
// Helper class that wraps a Vulkan command buffer.
class CommandBuffer final : public WrappedObject<VkCommandBuffer>
{
public:
CommandBuffer(VkDevice device, VkCommandPool commandPool);
~CommandBuffer() override;
Error begin();
Error end();
Error reset();
void singleImageBarrier(VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
const VkImageMemoryBarrier &imageMemoryBarrier);
private:
VkCommandPool mCommandPool;
};
class Image final : public WrappedObject<VkImage>
{
public:
// Use this constructor if the lifetime of the image is not controlled by ANGLE. (SwapChain)
Image();
explicit Image(VkImage image);
Image(Image &&other);
Image &operator=(Image &&other);
~Image() override;
void changeLayout(VkImageAspectFlags aspectMask,
VkImageLayout newLayout,
CommandBuffer *commandBuffer);
private:
VkImageLayout mCurrentLayout;
};
class ImageView final : public WrappedObject<VkImageView>
{
public:
ImageView();
explicit ImageView(VkDevice device);
ImageView(ImageView &&other);
ImageView &operator=(ImageView &&other);
~ImageView() override;
Error init(const VkImageViewCreateInfo &createInfo);
};
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
...@@ -70,4 +155,6 @@ inline Error NoError() ...@@ -70,4 +155,6 @@ inline Error NoError()
} \ } \
ANGLE_EMPTY_STATEMENT ANGLE_EMPTY_STATEMENT
#define ANGLE_VK_CHECK(test, error) ANGLE_VK_TRY(test ? VK_SUCCESS : error)
#endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_ #endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment