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
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
{
if (!mMessage)
......
......@@ -16,11 +16,33 @@
#include <string>
#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>
class ErrorOrResult;
ErrorOrResultBase(ResultT &&result) : mError(NoErrorVal), mResult(std::forward<ResultT>(result))
{
}
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
{
......@@ -53,6 +75,9 @@ class Error final
mutable std::unique_ptr<std::string> mMessage;
};
template <typename ResultT>
using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, GLenum, GL_NO_ERROR>;
namespace priv
{
template <GLenum EnumT>
......@@ -110,32 +135,6 @@ ErrorStream<EnumT> &ErrorStream<EnumT>::operator<<(T value)
using OutOfMemory = priv::ErrorStream<GL_OUT_OF_MEMORY>;
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()
{
return Error(GL_NO_ERROR);
......@@ -152,6 +151,7 @@ class Error final
explicit inline Error(EGLint errorCode);
Error(EGLint errorCode, 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(Error &&other);
......@@ -177,6 +177,9 @@ inline Error NoError()
return Error(EGL_SUCCESS);
}
template <typename ResultT>
using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, EGLint, EGL_SUCCESS>;
} // namespace egl
#define ANGLE_CONCAT1(x, y) x##y
......
......@@ -110,8 +110,13 @@ bool DisplayVk::isValidNativeWindow(EGLNativeWindowType window) const
std::string DisplayVk::getVendorString() const
{
// TODO(jmadill): Determine GPU vendor from Renderer.
return std::string("Google Inc.");
std::string vendorString = "Google Inc.";
if (mRenderer)
{
vendorString += " " + mRenderer->getVendorString();
}
return vendorString;
}
egl::Error DisplayVk::getDevice(DeviceImpl **device)
......@@ -137,7 +142,10 @@ SurfaceImpl *DisplayVk::createWindowSurface(const egl::SurfaceState &state,
EGLNativeWindowType window,
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,
......
......@@ -69,6 +69,8 @@ class DisplayVk : public DisplayImpl
const egl::AttributeMap &attribs) override;
gl::Version getMaxSupportedESVersion() const override;
RendererVk *getRenderer() const { return mRenderer.get(); }
private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override;
......
......@@ -10,6 +10,7 @@
#ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
#define LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
#include <memory>
#include <vulkan/vulkan.h>
#include "common/angleutils.h"
......@@ -32,9 +33,18 @@ class RendererVk : angle::NonCopyable
vk::Error initialize(const egl::AttributeMap &attribs);
std::string getVendorString() const;
std::string getRendererDescription() const;
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::TextureCapsMap &getNativeTextureCaps() const;
......@@ -54,9 +64,19 @@ class RendererVk : angle::NonCopyable
mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations;
vk::Error initializeDevice(uint32_t queueFamilyIndex);
VkInstance mInstance;
bool mEnableValidationLayers;
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
......
......@@ -10,7 +10,10 @@
#ifndef LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
#define LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/SurfaceImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
namespace rx
{
......@@ -49,7 +52,10 @@ class OffscreenSurfaceVk : public SurfaceImpl
class WindowSurfaceVk : public SurfaceImpl
{
public:
WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
WindowSurfaceVk(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window,
EGLint width,
EGLint height);
~WindowSurfaceVk() override;
egl::Error initialize(const DisplayImpl *displayImpl) override;
......@@ -70,6 +76,24 @@ class WindowSurfaceVk : public SurfaceImpl
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
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
......
......@@ -10,6 +10,7 @@
#include "renderervk_utils.h"
#include "common/debug.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx
{
......@@ -46,6 +47,28 @@ EGLint DefaultEGLErrorCode(VkResult result)
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
// Mirrors std_validation_str in loader.h
......@@ -116,6 +139,11 @@ const char *VulkanResultString(VkResult result)
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)
: mResult(result), mFile(file), mLine(line)
{
......@@ -175,6 +203,198 @@ bool Error::isError() const
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
bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps)
......
......@@ -28,6 +28,7 @@ namespace vk
class Error final
{
public:
Error(VkResult result);
Error(VkResult result, const char *file, unsigned int line);
~Error();
......@@ -50,12 +51,96 @@ class Error final
unsigned int mLine;
};
template <typename ResultT>
using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, VkResult, VK_SUCCESS>;
// Avoid conflicting with X headers which define "Success".
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 rx
......@@ -70,4 +155,6 @@ inline Error NoError()
} \
ANGLE_EMPTY_STATEMENT
#define ANGLE_VK_CHECK(test, error) ANGLE_VK_TRY(test ? VK_SUCCESS : error)
#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